📄 intelfbdrv.c
字号:
/* Enable device. */ if ((err = pci_enable_device(pdev))) { ERR_MSG("Cannot enable device.\n"); cleanup(dinfo); return -ENODEV; } /* Set base addresses. */ dinfo->fb_base_phys = pci_resource_start(pdev, 0); dinfo->mmio_base_phys = pci_resource_start(pdev, 1); DBG_MSG("fb region: 0x%lx/0x%lx, MMIO region: 0x%lx/0x%lx\n", pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); /* Reserve the fb and MMIO regions */ if (!request_mem_region(dinfo->fb_base_phys, pci_resource_len(pdev, 0), INTELFB_MODULE_NAME)) { ERR_MSG("Cannot reserve FB region.\n"); cleanup(dinfo); return -ENODEV; } if (!request_mem_region(dinfo->mmio_base_phys, pci_resource_len(pdev, 1), INTELFB_MODULE_NAME)) { ERR_MSG("Cannot reserve MMIO region.\n"); cleanup(dinfo); return -ENODEV; } /* Map the MMIO region. */ dinfo->mmio_base = (u32)ioremap(dinfo->mmio_base_phys, INTEL_REG_SIZE); if (!dinfo->mmio_base) { ERR_MSG("Cannot map MMIO.\n"); cleanup(dinfo); return -ENODEV; } /* Get the chipset info. */ dinfo->pci_chipset = pdev->device; if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, &dinfo->mobile)) { cleanup(dinfo); return -ENODEV; } if (intelfbhw_get_memory(pdev, &dinfo->aperture_size, &dinfo->stolen_size)) { cleanup(dinfo); return -ENODEV; } INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " "stolen memory %dkB\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dinfo->name, BtoMB(dinfo->aperture_size), BtoKB(dinfo->stolen_size)); /* Set these from the options. */ dinfo->accel = accel; dinfo->hwcursor = hwcursor; if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { INF_MSG("Acceleration is not supported for the %s chipset.\n", dinfo->name); dinfo->accel = 0; } /* * For now, set the video ram size to the stolen size rounded * down to a page multiple. This means the agpgart driver doesn't * need to get involved. */ dinfo->video_ram = ROUND_DOWN_TO_PAGE(dinfo->stolen_size); /* Allocate space for the ring buffer and HW cursor. */ if (dinfo->accel) { dinfo->ring_size = RINGBUFFER_SIZE; dinfo->video_ram -= dinfo->ring_size; dinfo->ring_base_phys = dinfo->fb_base_phys + dinfo->video_ram; dinfo->ring_tail_mask = dinfo->ring_size - 1; } if (dinfo->hwcursor && !dinfo->mobile) { dinfo->cursor_size = HW_CURSOR_SIZE; dinfo->video_ram -= dinfo->cursor_size; dinfo->cursor_offset = dinfo->video_ram; dinfo->cursor_base_phys = dinfo->fb_base_phys + dinfo->cursor_offset; } /* Framebuffer starts at offset 0. */ dinfo->fb_offset = 0; dinfo->video_ram -= dinfo->fb_offset; /* Map the FB region. Only map the memory used as video ram. */ dinfo->fb_base = (u32)ioremap(dinfo->fb_base_phys + dinfo->fb_offset, dinfo->video_ram); if (!dinfo->fb_base) { ERR_MSG("Cannot map framebuffer.\n"); cleanup(dinfo); return -ENODEV; } if (dinfo->accel) { /* Map the ring buffer. */ dinfo->ring_base = (u32)ioremap(dinfo->ring_base_phys, dinfo->ring_size); if (!dinfo->ring_base) { dinfo->accel = 0; WRN_MSG("Cannot map ring buffer: " "acceleration disabled.\n"); } } if (dinfo->hwcursor && !dinfo->mobile) { /* Map the HW cursor buffer. */ dinfo->cursor_base = (u32)ioremap(dinfo->cursor_base_phys, dinfo->cursor_size); if (!dinfo->cursor_base) { WRN_MSG("Cannot map the HW cursor space: " "HW cursor disabled.\n"); dinfo->hwcursor = 0; } } /* * For mobile platforms, a physical page address is needed for the * HW cursor. Allocate it here and insert it into the GTT. * If/when this driver is modified to be aware of the agpgart * driver, it can be used to obtain/insert the page. */ if (dinfo->hwcursor && dinfo->mobile) {#if !MOBILE_HW_CURSOR dinfo->hwcursor = 0; INF_MSG("HW cursor is not supported for mobile platforms.\n");#else struct page *pg; /* * Allocate a page of physical memory for the graphics * engine to write to for synchronisation purposes. */ pg = alloc_page(GFP_KERNEL); if (!pg) { WRN_MSG("Cannot allocate a page for the HW cursor. " "Disabling the HW cursor."); dinfo->hwcursor = 0; } else { get_page(pg); LockPage(pg); dinfo->cursor_page_virt = (u32)page_address(pg); dinfo->cursor_base_real = virt_to_phys(page_address(pg)); /* * XXX Add code to insert GTT entry and map the * appropriate part of the aperture as * dinfo->cursor_base. */ }#endif } DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", dinfo->fb_base_phys, dinfo->fb_offset, dinfo->video_ram, dinfo->fb_base); DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", dinfo->mmio_base_phys, INTEL_REG_SIZE, dinfo->mmio_base); DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", dinfo->ring_base_phys, dinfo->ring_size, dinfo->ring_base); DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", dinfo->cursor_base_phys, dinfo->cursor_size, dinfo->cursor_base, dinfo->cursor_offset, dinfo->cursor_base_real); DBG_MSG("options: accel = %d, fixed = %d, noinit = %d\n", accel, fixed, noinit); DBG_MSG("options: mode = \"%s\", font = \"%s\"\n", mode ? mode : "", font ? font : ""); if (probeonly) bailout(dinfo); dinfo->fixed_mode = fixed; /* * Check if the LVDS port or any DVO ports are enabled. If so, * don't allow mode switching. */ if ((s = intelfbhw_check_non_crt(dinfo))) { WRN_MSG("Non-CRT device is enabled (%s). " "Disabling mode switching.\n", s); dinfo->fixed_mode = 1; } if (bailearly == 1) bailout(dinfo); if (dinfo->fixed_mode && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) { ERR_MSG("Video mode must be programmed at boot time.\n"); cleanup(dinfo); return -ENODEV; } if (bailearly == 2) bailout(dinfo); /* Initialise dinfo and related data. */ /* If an initial mode was programmed at boot time, get its details. */ if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) get_initial_mode(dinfo); if (bailearly == 3) bailout(dinfo);#if 0 if (dinfo->fixed_mode) { /* * XXX Check video ram amounts and remap if the region already * mapped is too small because of ring/cursor allocations. */ update_dinfo(dinfo, &dinfo->initial_var, NULL); }#endif /* currcon will be set by the first switch. */ dinfo->currcon = -1; dinfo->vc_mode = KD_TEXT;#if USE_SYNC_PAGE if (dinfo->accel) { struct page *pg; /* * Allocate a page of physical memory for the graphics * engine to write to for synchronisation purposes. */ pg = alloc_page(GFP_KERNEL); if (!pg) { WRN_MSG("Cannot allocate a page for 2D accel. " "Disabling acceleration."); dinfo->accel = 0; } else { get_page(pg); LockPage(pg); dinfo->syncpage_virt = (u32)page_address(pg); dinfo->syncpage_phys = virt_to_phys(page_address(pg)); /* Write zero to the first dword */ writel(0, dinfo->syncpage_virt); DBG_MSG("2D sync page: 0x%x (0x%x)\n", dinfo->syncpage_phys, dinfo->syncpage_virt); } }#endif if (bailearly == 4) bailout(dinfo); if (intelfb_set_fbinfo(dinfo)) { cleanup(dinfo); return -ENODEV; } if (bailearly == 5) bailout(dinfo); for (i = 0; i < 16; i++) { j = color_table[i]; dinfo->palette[i].red = default_red[j]; dinfo->palette[i].green = default_grn[j]; dinfo->palette[i].blue = default_blu[j]; } if (bailearly == 6) bailout(dinfo); pci_set_drvdata(pdev, dinfo); /* Save the initial register state. */ i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, bailearly > 6 ? bailearly - 6 : 0); if (i != 0) { DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); bailout(dinfo); } intelfbhw_print_hw_state(dinfo, &dinfo->save_state); if (bailearly == 18) bailout(dinfo);#if TEST_MODE_TO_HW { struct intelfb_hwstate hw; struct fb_var_screeninfo var; int i; for (i = 0; i < num_modes; i++) { mode_to_var(&modedb[i], &var, 8); intelfbhw_read_hw_state(dinfo, &hw, 0); if (intelfbhw_mode_to_hw(dinfo, &hw, &var)) { DGB_MSG("Failed to set hw for mode %dx%d\n", var.xres, var.yres); } else { DGB_MSG("HW state for mode %dx%d\n", var.xres, var.yres); intelfbhw_print_hw_state(dinfo, &hw); } } }#endif /* Cursor initialisation */ if (dinfo->hwcursor) { init_timer(&dinfo->cursor.timer); dinfo->cursor.timer.function = intelfb_flashcursor; dinfo->cursor.timer.data = (unsigned long)dinfo; dinfo->cursor.state = CM_ERASE; spin_lock_init(&dinfo->DAClock); } if (bailearly == 19) bailout(dinfo); if (noregister) bailout(dinfo); if (register_framebuffer(&(dinfo->info)) < 0) { ERR_MSG("Cannot register framebuffer.\n"); cleanup(dinfo); return -ENODEV; } dinfo->registered = 1; return 0;}static void __devexitintelfb_pci_unregister(struct pci_dev *pdev){ struct intelfb_info *dinfo = pci_get_drvdata(pdev); DBG_MSG("intelfb_pci_unregister\n"); if (!dinfo) return; cleanup(dinfo); pci_set_drvdata(pdev, NULL);}/* * A simplified version of fb_find_mode. The latter doesn't seem to work * too well -- haven't figured out why yet. */static intintelfb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, const char *mode_option, const struct fb_videomode *db, unsigned int dbsize, const struct fb_videomode *default_mode, unsigned int default_bpp){ int i; char mname[20] = "", tmp[20] = "", *p, *q; unsigned int bpp = 0; DBG_MSG("intelfb_find_mode\n"); /* Set up defaults */ if (!db) { db = modedb; dbsize = sizeof(modedb) / sizeof(*modedb); } if (!default_bpp)#if defined(FBCON_HAS_CFB8) default_bpp = 8;#elif defined(FBCON_HAS_CFB16) default_bpp = 16;#elif defined(FBCON_HAS_CFB32) default_bpp = 32;#endif var->activate = FB_ACTIVATE_TEST; if (mode_option && *mode_option) { if (strlen(mode_option) < sizeof(tmp) - 1) { strcat(tmp, mode_option); q = tmp; p = strsep(&q, "-"); strcat(mname, p); if (q) { p = strsep(&q, "@"); bpp = simple_strtoul(p, NULL, 10); if (q) { strcat(mname, "@"); strcat(mname, q); } } } if (!bpp) bpp = default_bpp; DBG_MSG("Mode is %s, bpp %d\n", mname, bpp); } if (*mname) { for (i = 0; i < dbsize; i++) { if (!strncmp(db[i].name, mname, strlen(mname))) { mode_to_var(&db[i], var, bpp); if (!intelfb_set_var(var, -1, info)) return 1; } } } if (!default_mode) return 0; mode_to_var(default_mode, var, default_bpp); if (!intelfb_set_var(var, -1, info)) return 3; for (i = 0; i < dbsize; i++) { mode_to_var(&db[i], var, default_bpp); if (!intelfb_set_var(var, -1, info)) return 4; } return 0;}static __inline__ intvar_to_refresh(const struct fb_var_screeninfo *var){ int xtot = var->xres + var->left_margin + var->right_margin + var->hsync_len; int ytot = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;}/* Various intialisation functions */static int __devinitintelfb_init_disp_var(struct intelfb_info *dinfo){ int msrc = 0; DBG_MSG("intelfb_init_disp_var\n"); if (dinfo->fixed_mode) { dinfo->disp.var = dinfo->initial_var; msrc = 5; } else { if (mode) { msrc = intelfb_find_mode(&dinfo->disp.var, &dinfo->info, mode, modedb, num_modes, NULL, 0); if (msrc) msrc |= 8; } if (!msrc) { msrc = intelfb_find_mode(&dinfo->disp.var, &dinfo->info, PREFERRED_MODE, modedb, num_modes, &modedb[DFLT_MODE], 0); } } if (!msrc) { ERR_MSG("Cannot find a suitable video mode.\n"); return 1; } INF_MSG("Initial video mode is %dx%d-%d@%d.\n", dinfo->disp.var.xres, dinfo->disp.var.yres, intelfb_var_to_depth(&dinfo->disp.var), var_to_refresh(&dinfo->disp.var)); DBG_MSG("Initial video mode is from %d.\n", msrc); if (dinfo->accel) dinfo->disp.var.accel_flags |= FB_ACCELF_TEXT; else dinfo->disp.var.accel_flags &= ~FB_ACCELF_TEXT; return 0;}static voidintelfb_set_dispsw(struct intelfb_info *dinfo, struct display *disp){ DBG_MSG("intelfb_set_dispsw: (bpp is %d)\n", disp->var.bits_per_pixel); disp->dispsw_data = NULL; disp->dispsw = NULL; switch (disp->var.bits_per_pixel) {#ifdef FBCON_HAS_CFB8 case 8: break;#endif#ifdef FBCON_HAS_CFB16 case 16: disp->dispsw_data = &dinfo->con_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB32 case 32: disp->dispsw_data = &dinfo->con_cmap.cfb32; break;#endif default: WRN_MSG("Setting fbcon_dummy renderer (bpp is %d).\n", disp->var.bits_per_pixel); disp->dispsw = &fbcon_dummy; } /* For all supported bpp. */ if (!disp->dispsw) disp->dispsw = &fbcon_intelfb;}static int __devinitintelfb_init_disp(struct intelfb_info *dinfo){ struct fb_info *info; struct display *disp; DBG_MSG("intelfb_init_disp\n"); info = &dinfo->info; disp = &dinfo->disp; if (intelfb_init_disp_var(dinfo)) return 1; info->disp = disp; update_dinfo(dinfo, &disp->var, disp); intelfb_set_dispsw(dinfo, disp); dinfo->currcon_display = disp; return 0;}static int __devinitintelfb_set_fbinfo(struct intelfb_info *dinfo){ struct fb_info *info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -