static void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct intelfb_info *dinfo = GET_DINFO(info); u32 fgcolor, bgcolor; #if VERBOSE > 0 DBG_MSG("intelfb_imageblit\n"); #endif if (!ACCEL(dinfo, info) || dinfo->depth == 4 || image->depth != 1) { cfb_imageblit(info, image); return; } if (dinfo->depth != 8) { fgcolor = dinfo->pseudo_palette[image->fg_color]; bgcolor = dinfo->pseudo_palette[image->bg_color]; } else { fgcolor = image->fg_color; bgcolor = image->bg_color; } if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, image->height, image->data, image->dx, image->dy, dinfo->pitch, info->var.bits_per_pixel)) { cfb_imageblit(info, image); return; } } /* fb ops */ static struct fb_ops intel_fb_ops = { .owner = THIS_MODULE, .fb_open = intelfb_open, .fb_release = intelfb_release, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, .fb_blank = intelfb_blank, .fb_pan_display = intelfb_pan_display, .fb_fillrect = intelfb_fillrect, .fb_copyarea = intelfb_copyarea, .fb_imageblit = intelfb_imageblit, .fb_cursor = intelfb_cursor, .fb_sync = intelfb_sync, .fb_ioctl = intelfb_ioctl }; /* PCI driver module table */ static struct pci_driver intelfb_driver = { .name = "intelfb", .id_table = intelfb_pci_table, .probe = intelfb_pci_register, .remove = __devexit_p(intelfb_pci_unregister) }; static int __devinit intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { struct fb_info *info; struct intelfb_info *dinfo; int i, err, dvo; int aperture_size, stolen_size; struct agp_kern_info gtt_info; int agp_memtype; const char *s; struct agp_bridge_data *bridge; int aperture_bar = 0; int mmio_bar = 1; int offset; DBG_MSG("intelfb_pci_register\n"); num_registered++; if (num_registered != 1) { ERR_MSG("Attempted to register %d devices " "(should be only 1).\n", num_registered); return -ENODEV; } info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); if (!info) { ERR_MSG("Could not allocate memory for intelfb_info.\n"); return -ENODEV; } if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { ERR_MSG("Could not allocate cmap for intelfb_info.\n"); goto err_out_cmap; return -ENODEV; } dinfo = info->par; dinfo->info = info; dinfo->fbops = &intel_fb_ops; dinfo->pdev = pdev; /* Reserve pixmap space. */ info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL); if (info->pixmap.addr == NULL) { ERR_MSG("Cannot reserve pixmap memory.\n"); goto err_out_pixmap; } /* set early this option because it could be changed by tv encoder driver */ dinfo->fixed_mode = fixed; /* Enable device. */ if ((err = pci_enable_device(pdev))) { ERR_MSG("Cannot enable device.\n"); cleanup(dinfo); return -ENODEV; } /* Set base addresses. */ if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || (ent->device == PCI_DEVICE_ID_INTEL_945GM) || (ent->device == PCI_DEVICE_ID_INTEL_945GME) || (ent->device == PCI_DEVICE_ID_INTEL_965G) || (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { aperture_bar = 2; mmio_bar = 0; } dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", (unsigned long long)pci_resource_start(pdev, aperture_bar), (unsigned long long)pci_resource_len(pdev, aperture_bar), (unsigned long long)pci_resource_start(pdev, mmio_bar), (unsigned long long)pci_resource_len(pdev, mmio_bar)); /* Reserve the fb and MMIO regions */ if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, INTELFB_MODULE_NAME)) { ERR_MSG("Cannot reserve FB region.\n"); cleanup(dinfo); return -ENODEV; } dinfo->flag |= INTELFB_FB_ACQUIRED; if (!request_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE, INTELFB_MODULE_NAME)) { ERR_MSG("Cannot reserve MMIO region.\n"); cleanup(dinfo); return -ENODEV; } dinfo->flag |= INTELFB_MMIO_ACQUIRED; /* Get the chipset info. */ dinfo->pci_chipset = pdev->device; if (intelfbhw_get_chipset(pdev, dinfo)) { cleanup(dinfo); return -ENODEV; } if (intelfbhw_get_memory(pdev, &aperture_size,&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(aperture_size), BtoKB(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; } /* Framebuffer parameters - Use all the stolen memory if >= vram */ if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); dinfo->fbmem_gart = 0; } else { dinfo->fb.size = MB(vram); dinfo->fbmem_gart = 1; } /* Allocate space for the ring buffer and HW cursor if enabled. */ if (dinfo->accel) { dinfo->ring.size = RINGBUFFER_SIZE; dinfo->ring_tail_mask = dinfo->ring.size - 1; } if (dinfo->hwcursor) dinfo->cursor.size = HW_CURSOR_SIZE; /* Use agpgart to manage the GATT */ if (!(bridge = agp_backend_acquire(pdev))) { ERR_MSG("cannot acquire agp\n"); cleanup(dinfo); return -ENODEV; } /* get the current gatt info */ if (agp_copy_info(bridge, >t_info)) { ERR_MSG("cannot get agp info\n"); agp_backend_release(bridge); cleanup(dinfo); return -ENODEV; } if (MB(voffset) < stolen_size) offset = (stolen_size >> 12); else offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; /* set the mem offsets - set them after the already used pages */ if (dinfo->accel) dinfo->ring.offset = offset + gtt_info.current_memory; if (dinfo->hwcursor) dinfo->cursor.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12); if (dinfo->fbmem_gart) dinfo->fb.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12) + (dinfo->cursor.size >> 12); /* Allocate memories (which aren't stolen) */ /* Map the fb and MMIO regions */ /* ioremap only up to the end of used aperture */ dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache (dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12) + dinfo->fb.size); if (!dinfo->aperture.virtual) { ERR_MSG("Cannot remap FB region.\n"); cleanup(dinfo); return -ENODEV; } dinfo->mmio_base = (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, INTEL_REG_SIZE); if (!dinfo->mmio_base) { ERR_MSG("Cannot remap MMIO region.\n"); cleanup(dinfo); return -ENODEV; } if (dinfo->accel) { if (!(dinfo->gtt_ring_mem = agp_allocate_memory(bridge, dinfo->ring.size >> 12, AGP_NORMAL_MEMORY))) { ERR_MSG("cannot allocate ring buffer memory\n"); agp_backend_release(bridge); cleanup(dinfo); return -ENOMEM; } if (agp_bind_memory(dinfo->gtt_ring_mem, dinfo->ring.offset)) { ERR_MSG("cannot bind ring buffer memory\n"); agp_backend_release(bridge); cleanup(dinfo); return -EBUSY; } dinfo->ring.physical = dinfo->aperture.physical + (dinfo->ring.offset << 12); dinfo->ring.virtual = dinfo->aperture.virtual + (dinfo->ring.offset << 12); dinfo->ring_head = 0; } if (dinfo->hwcursor) { agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY : AGP_NORMAL_MEMORY; if (!(dinfo->gtt_cursor_mem = agp_allocate_memory(bridge, dinfo->cursor.size >> 12, agp_memtype))) { ERR_MSG("cannot allocate cursor memory\n"); agp_backend_release(bridge); cleanup(dinfo); return -ENOMEM; } if (agp_bind_memory(dinfo->gtt_cursor_mem, dinfo->cursor.offset)) { ERR_MSG("cannot bind cursor memory\n"); agp_backend_release(bridge); cleanup(dinfo); return -EBUSY; } if (dinfo->mobile) dinfo->cursor.physical = dinfo->gtt_cursor_mem->physical; else dinfo->cursor.physical = dinfo->aperture.physical + (dinfo->cursor.offset << 12); dinfo->cursor.virtual = dinfo->aperture.virtual + (dinfo->cursor.offset << 12); } if (dinfo->fbmem_gart) { if (!(dinfo->gtt_fb_mem = agp_allocate_memory(bridge, dinfo->fb.size >> 12, AGP_NORMAL_MEMORY))) { WRN_MSG("cannot allocate framebuffer memory - use " "the stolen one\n"); dinfo->fbmem_gart = 0; } if (agp_bind_memory(dinfo->gtt_fb_mem, dinfo->fb.offset)) { WRN_MSG("cannot bind framebuffer memory - use " "the stolen one\n"); dinfo->fbmem_gart = 0; } } /* update framebuffer memory parameters */ if (!dinfo->fbmem_gart) dinfo->fb.offset = 0; /* starts at offset 0 */ dinfo->fb.physical = dinfo->aperture.physical + (dinfo->fb.offset << 12); dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); dinfo->fb_start = dinfo->fb.offset << 12; /* release agpgart */ agp_backend_release(bridge); if (mtrr) set_mtrr(dinfo); DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n", dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, dinfo->fb.virtual); DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n", dinfo->mmio_base_phys, INTEL_REG_SIZE, dinfo->mmio_base); DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n", dinfo->ring.physical, dinfo->ring.size, dinfo->ring.virtual); DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n", dinfo->cursor.physical, dinfo->cursor.size, dinfo->cursor.virtual, dinfo->cursor.offset, dinfo->cursor.physical); DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); if (probeonly) bailout(dinfo); /* * Check if the LVDS port or any DVO ports are enabled. If so, * don't allow mode switching */ dvo = intelfbhw_check_non_crt(dinfo); if (dvo) { dinfo->fixed_mode = 1; WRN_MSG("Non-CRT device is enabled ( "); i = 0; while (dvo) { if (dvo & 1) { s = intelfbhw_dvo_to_string(1 << i); if (s) printk("%s ", s); } dvo >>= 1; ++i; } printk("). Disabling mode switching.\n"); } if (bailearly == 1) bailout(dinfo); if (FIXED_MODE(dinfo) && screen_info.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 (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) get_initial_mode(dinfo); if (bailearly == 3) bailout(dinfo); if (FIXED_MODE(dinfo)) /* remap fb address */ update_dinfo(dinfo, &dinfo->initial_var); if (bailearly == 4) bailout(dinfo); if (intelfb_set_fbinfo(dinfo)) { cleanup(dinfo); return -ENODEV; } if (bailearly == 5) bailout(dinfo); #ifdef CONFIG_FB_INTEL_I2C /* register I2C bus */ intelfb_create_i2c_busses(dinfo); #endif 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); /* Cursor initialisation */ if (dinfo->hwcursor) { intelfbhw_cursor_init(dinfo); intelfbhw_cursor_reset(dinfo); } if (bailearly == 19) bailout(dinfo); /* 2d acceleration init */ if (dinfo->accel) intelfbhw_2d_start(dinfo); if (bailearly == 20) 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; dinfo->open = 0; init_waitqueue_head(&dinfo->vsync.wait); spin_lock_init(&dinfo->int_lock); dinfo->irq_flags = 0; dinfo->vsync.pan_display = 0; dinfo->vsync.pan_offset = 0; return 0; err_out_pixmap: fb_dealloc_cmap(&info->cmap); err_out_cmap: framebuffer_release(info); return -ENODEV; } ffffffff80396480 T cfb_copyarea ffffffff8039615d T cfb_fillrect ffffffff80396dfc T cfb_imageblit ffffffff8053bc60 r cfb_tab16_le ffffffff8053bc70 r cfb_tab32 ffffffff8053bc20 r cfb_tab8_le ffffffff8038f6bb t con2fb_acquire_newinfo ffffffff80881130 b con2fb_map ffffffff80881170 b con2fb_map_boot ffffffff803848b9 t do_fb_ioctl ffffffff803889f7 T fb_add_videomode ffffffff803876a8 T fb_alloc_cmap ffffffff80387909 T fb_bl_default_curve ffffffff80383d11 T fb_blank ffffffff8087f0c0 B fb_class ffffffff80387996 T fb_cleanup_device ffffffff80387393 T fb_cmap_to_user ffffffff8053a210 r fb_con ffffffff80776fc9 t fb_console_init ffffffff80776d90 t fb_console_setup ffffffff80387485 T fb_copy_cmap ffffffff8038653a t fb_create_modedb ffffffff80539dc0 r fb_cvt_vbi_tab ffffffff80387648 T fb_dealloc_cmap ffffffff803872c0 T fb_default_cmap ffffffff80388973 T fb_delete_videomode ffffffff80385aa9 T fb_destroy_modedb ffffffff80388932 T fb_destroy_modelist ffffffff8087f1b0 b fb_display ffffffff80386bdf T fb_edid_to_monspecs ffffffff8038883f T fb_find_best_display ffffffff803887ca T fb_find_best_mode ffffffff804f4b7e T fb_find_logo ffffffff80388b3c T fb_find_mode ffffffff80389180 T fb_find_mode_cvt ffffffff8038874b T fb_find_nearest_mode ffffffff80385a9c T fb_firmware_edid ffffffff8038c2c5 t fb_flashcursor ffffffff80538510 r fb_fops ffffffff803837c0 T fb_get_buffer_offset ffffffff8038364c T fb_get_color_depth ffffffff80385b8d T fb_get_mode ffffffff8038419b T fb_get_options ffffffff80385858 t fb_get_vblank ffffffff8038838b T fb_init_device ffffffff803872fb T fb_invert_cmaps ffffffff80384cf9 t fb_ioctl ffffffff8074a590 d fb_logo ffffffff803886cf T fb_match_mode ffffffff80383b16 t fb_mmap ffffffff80388682 T fb_mode_is_equal ffffffff8087f0c8 B fb_mode_option ffffffff80384d21 T fb_new_modelist ffffffff803835f8 T fb_notifier_call_chain ffffffff803955c8 t fb_notifier_callback ffffffff806e2450 d fb_notifier_list ffffffff80383a21 t fb_open ffffffff80383686 T fb_pad_aligned_buffer ffffffff803836c3 T fb_pad_unaligned_buffer ffffffff80383891 T fb_pan_display ffffffff8038632d T fb_parse_edid ffffffff803856fc T fb_prepare_logo ffffffff80538440 r fb_proc_fops ffffffff80383f76 t fb_read ffffffff8038362f T fb_register_client ffffffff80383991 t fb_release ffffffff80383868 t fb_seq_next ffffffff80384167 t fb_seq_show ffffffff80383853 t fb_seq_start ffffffff80383886 t fb_seq_stop ffffffff8038753a T fb_set_cmap ffffffff80383ca9 T fb_set_suspend ffffffff803877ae T fb_set_user_cmap ffffffff8038462e T fb_set_var ffffffff80384e2c T fb_show_logo ffffffff80385ab9 t fb_timings_dclk ffffffff8038590b t fb_timings_hfreq ffffffff80385881 t fb_timings_vfreq ffffffff803884a4 t fb_try_mode ffffffff80383615 T fb_unregister_client ffffffff80385973 T fb_validate_mode ffffffff80388539 T fb_var_to_videomode ffffffff80388af3 T fb_videomode_to_modelist ffffffff80388611 T fb_videomode_to_var ffffffff80383d7a t fb_write ffffffff808811e4 b first_fb_vc ffffffff8088af18 b ip_fb_id_lock.45546 ffffffff806e2814 d last_fb_vc ffffffff803839e8 T lock_fb_info ffffffff8038414d t proc_fb_open ffffffff805385e0 r proc_fb_seq_ops ffffffff8039046d t set_con2fb_map ffffffff80798ff0 t vesafb_defined ffffffff808812b8 b vesafb_device ffffffff806e2a80 d vesafb_driver ffffffff80798fa0 t vesafb_fix ffffffff8077784c t vesafb_init ffffffff806e2b20 d vesafb_ops ffffffff80397264 t vesafb_pan_display ffffffff80777152 t vesafb_probe ffffffff80397271 t vesafb_setcolreg |