📄 neofb.c
字号:
printk(KERN_INFO "neofb: mapped io at %p\n", par->mmio_vbase); return 0;}static void neo_unmap_mmio(struct fb_info *info){ struct neofb_par *par = info->par; DBG("neo_unmap_mmio"); iounmap(par->mmio_vbase); par->mmio_vbase = NULL; release_mem_region(info->fix.mmio_start, info->fix.mmio_len);}static int __devinit neo_map_video(struct fb_info *info, struct pci_dev *dev, int video_len){ //unsigned long addr; DBG("neo_map_video"); info->fix.smem_start = pci_resource_start(dev, 0); info->fix.smem_len = video_len; if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, "frame buffer")) { printk("neofb: frame buffer in use\n"); return -EBUSY; } info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) { printk("neofb: unable to map screen memory\n"); release_mem_region(info->fix.smem_start, info->fix.smem_len); return -ENOMEM; } else printk(KERN_INFO "neofb: mapped framebuffer at %p\n", info->screen_base);#ifdef CONFIG_MTRR ((struct neofb_par *)(info->par))->mtrr = mtrr_add(info->fix.smem_start, pci_resource_len(dev, 0), MTRR_TYPE_WRCOMB, 1);#endif /* Clear framebuffer, it's all white in memory after boot */ memset_io(info->screen_base, 0, info->fix.smem_len); /* Allocate Cursor drawing pad. info->fix.smem_len -= PAGE_SIZE; addr = info->fix.smem_start + info->fix.smem_len; write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) | ((0x0ff0 & (addr >> 10)) >> 4), par); addr = (unsigned long) info->screen_base + info->fix.smem_len; info->sprite.addr = (u8 *) addr; */ return 0;}static void neo_unmap_video(struct fb_info *info){ DBG("neo_unmap_video");#ifdef CONFIG_MTRR { struct neofb_par *par = info->par; mtrr_del(par->mtrr, info->fix.smem_start, info->fix.smem_len); }#endif iounmap(info->screen_base); info->screen_base = NULL; release_mem_region(info->fix.smem_start, info->fix.smem_len);}static int __devinit neo_scan_monitor(struct fb_info *info){ struct neofb_par *par = info->par; unsigned char type, display; int w; // Eventually we will have i2c support. info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL); if (!info->monspecs.modedb) return -ENOMEM; info->monspecs.modedb_len = 1; /* Determine the panel type */ vga_wgfx(NULL, 0x09, 0x26); type = vga_rgfx(NULL, 0x21); display = vga_rgfx(NULL, 0x20); if (!par->internal_display && !par->external_display) { par->internal_display = display & 2 || !(display & 3) ? 1 : 0; par->external_display = display & 1; printk (KERN_INFO "Autodetected %s display\n", par->internal_display && par->external_display ? "simultaneous" : par->internal_display ? "internal" : "external"); } /* Determine panel width -- used in NeoValidMode. */ w = vga_rgfx(NULL, 0x20); vga_wgfx(NULL, 0x09, 0x00); switch ((w & 0x18) >> 3) { case 0x00: // 640x480@60 par->NeoPanelWidth = 640; par->NeoPanelHeight = 480; memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); break; case 0x01: par->NeoPanelWidth = 800; if (par->libretto) { par->NeoPanelHeight = 480; memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode)); } else { // 800x600@60 par->NeoPanelHeight = 600; memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode)); } break; case 0x02: // 1024x768@60 par->NeoPanelWidth = 1024; par->NeoPanelHeight = 768; memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode)); break; case 0x03: /* 1280x1024@60 panel support needs to be added */#ifdef NOT_DONE par->NeoPanelWidth = 1280; par->NeoPanelHeight = 1024; memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode)); break;#else printk(KERN_ERR "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n"); return -1;#endif default: // 640x480@60 par->NeoPanelWidth = 640; par->NeoPanelHeight = 480; memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); break; } printk(KERN_INFO "Panel is a %dx%d %s %s display\n", par->NeoPanelWidth, par->NeoPanelHeight, (type & 0x02) ? "color" : "monochrome", (type & 0x10) ? "TFT" : "dual scan"); return 0;}static int __devinit neo_init_hw(struct fb_info *info){ struct neofb_par *par = info->par; int videoRam = 896; int maxClock = 65000; int CursorMem = 1024; int CursorOff = 0x100; DBG("neo_init_hw"); neoUnlock();#if 0 printk(KERN_DEBUG "--- Neo extended register dump ---\n"); for (int w = 0; w < 0x85; w++) printk(KERN_DEBUG "CR %p: %p\n", (void *) w, (void *) vga_rcrt(NULL, w)); for (int w = 0; w < 0xC7; w++) printk(KERN_DEBUG "GR %p: %p\n", (void *) w, (void *) vga_rgfx(NULL, w));#endif switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: videoRam = 896; maxClock = 65000; break; case FB_ACCEL_NEOMAGIC_NM2090: case FB_ACCEL_NEOMAGIC_NM2093: case FB_ACCEL_NEOMAGIC_NM2097: videoRam = 1152; maxClock = 80000; break; case FB_ACCEL_NEOMAGIC_NM2160: videoRam = 2048; maxClock = 90000; break; case FB_ACCEL_NEOMAGIC_NM2200: videoRam = 2560; maxClock = 110000; break; case FB_ACCEL_NEOMAGIC_NM2230: videoRam = 3008; maxClock = 110000; break; case FB_ACCEL_NEOMAGIC_NM2360: videoRam = 4096; maxClock = 110000; break; case FB_ACCEL_NEOMAGIC_NM2380: videoRam = 6144; maxClock = 110000; break; } switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: case FB_ACCEL_NEOMAGIC_NM2090: case FB_ACCEL_NEOMAGIC_NM2093: CursorMem = 2048; CursorOff = 0x100; break; case FB_ACCEL_NEOMAGIC_NM2097: case FB_ACCEL_NEOMAGIC_NM2160: CursorMem = 1024; CursorOff = 0x100; break; case FB_ACCEL_NEOMAGIC_NM2200: case FB_ACCEL_NEOMAGIC_NM2230: case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2380: CursorMem = 1024; CursorOff = 0x1000; par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; break; }/* info->sprite.size = CursorMem; info->sprite.scan_align = 1; info->sprite.buf_align = 1; info->sprite.flags = FB_PIXMAP_IO; info->sprite.outbuf = neofb_draw_cursor;*/ par->maxClock = maxClock; par->cursorOff = CursorOff; return videoRam * 1024;}static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id){ struct fb_info *info; struct neofb_par *par; info = framebuffer_alloc(sizeof(struct neofb_par), &dev->dev); if (!info) return NULL; par = info->par; info->fix.accel = id->driver_data; par->pci_burst = !nopciburst; par->lcd_stretch = !nostretch; par->libretto = libretto; par->internal_display = internal; par->external_display = external; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 128"); break; case FB_ACCEL_NEOMAGIC_NM2090: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 128V"); break; case FB_ACCEL_NEOMAGIC_NM2093: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 128ZV"); break; case FB_ACCEL_NEOMAGIC_NM2097: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 128ZV+"); break; case FB_ACCEL_NEOMAGIC_NM2160: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 128XD"); break; case FB_ACCEL_NEOMAGIC_NM2200: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 256AV"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2230: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 256AV+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2360: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 256ZX"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2380: snprintf(info->fix.id, sizeof(info->fix.id), "MagicGraph 256XL+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; } info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type_aux = 0; info->fix.xpanstep = 0; info->fix.ypanstep = 4; info->fix.ywrapstep = 0; info->fix.accel = id->driver_data; info->fbops = &neofb_ops; info->pseudo_palette = par->palette; return info;}static void neo_free_fb_info(struct fb_info *info){ if (info) { /* * Free the colourmap */ fb_dealloc_cmap(&info->cmap); framebuffer_release(info); }}/* --------------------------------------------------------------------- */static int __devinit neofb_probe(struct pci_dev *dev, const struct pci_device_id *id){ struct fb_info *info; u_int h_sync, v_sync; int video_len, err; DBG("neofb_probe"); err = pci_enable_device(dev); if (err) return err; err = -ENOMEM; info = neo_alloc_fb_info(dev, id); if (!info) return err; err = neo_map_mmio(info, dev); if (err) goto err_map_mmio; err = neo_scan_monitor(info); if (err) goto err_scan_monitor; video_len = neo_init_hw(info); if (video_len < 0) { err = video_len; goto err_init_hw; } err = neo_map_video(info, dev, video_len); if (err) goto err_init_hw; if (!fb_find_mode(&info->var, info, mode_option, NULL, 0, info->monspecs.modedb, 16)) { printk(KERN_ERR "neofb: Unable to find usable video mode.\n"); goto err_map_video; } /* * Calculate the hsync and vsync frequencies. Note that * we split the 1e12 constant up so that we can preserve * the precision and fit the results into 32-bit registers. * (1953125000 * 512 = 1e12) */ h_sync = 1953125000 / info->var.pixclock; h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len); v_sync = h_sync / (info->var.yres + info->var.upper_margin + info->var.lower_margin + info->var.vsync_len); printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", info->fix.smem_len >> 10, info->var.xres, info->var.yres, h_sync / 1000, h_sync % 1000, v_sync); if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) goto err_map_video; err = register_framebuffer(info); if (err < 0) goto err_reg_fb; printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); /* * Our driver data */ pci_set_drvdata(dev, info); return 0;err_reg_fb: fb_dealloc_cmap(&info->cmap);err_map_video: neo_unmap_video(info);err_init_hw: fb_destroy_modedb(info->monspecs.modedb);err_scan_monitor: neo_unmap_mmio(info);err_map_mmio: neo_free_fb_info(info); return err;}static void __devexit neofb_remove(struct pci_dev *dev){ struct fb_info *info = pci_get_drvdata(dev); DBG("neofb_remove"); if (info) { /* * If unregister_framebuffer fails, then * we will be leaving hooks that could cause * oopsen laying around. */ if (unregister_framebuffer(info)) printk(KERN_WARNING "neofb: danger danger! Oopsen imminent!\n"); neo_unmap_video(info); fb_destroy_modedb(info->monspecs.modedb); neo_unmap_mmio(info); neo_free_fb_info(info); /* * Ensure that the driver data is no longer * valid. */ pci_set_drvdata(dev, NULL); }}static struct pci_device_id neofb_devices[] = { {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360}, {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380}, {0, 0, 0, 0, 0, 0, 0}};MODULE_DEVICE_TABLE(pci, neofb_devices);static struct pci_driver neofb_driver = { .name = "neofb", .id_table = neofb_devices, .probe = neofb_probe, .remove = __devexit_p(neofb_remove)};/* ************************* init in-kernel code ************************** */#ifndef MODULEstatic int __init neofb_setup(char *options){ char *this_opt; DBG("neofb_setup"); if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; if (!strncmp(this_opt, "internal", 8)) internal = 1; else if (!strncmp(this_opt, "external", 8)) external = 1; else if (!strncmp(this_opt, "nostretch", 9)) nostretch = 1; else if (!strncmp(this_opt, "nopciburst", 10)) nopciburst = 1; else if (!strncmp(this_opt, "libretto", 8)) libretto = 1; else mode_option = this_opt; } return 0;}#endif /* MODULE */static int __init neofb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("neofb", &option)) return -ENODEV; neofb_setup(option);#endif return pci_register_driver(&neofb_driver);}module_init(neofb_init);#ifdef MODULEstatic void __exit neofb_exit(void){ pci_unregister_driver(&neofb_driver);}module_exit(neofb_exit);#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -