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, &gtt_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

Reply via email to