framebuf操作源码

虚拟机ubuntu,Ctrl+Alt+F1切换到图形模式,Ctrl+Alt+F6切换到命令行模式

framebuf在图形模式下无效,需要切换到命令行模式

vir2phy.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
// 参考
 
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
 
#define    page_map_file     "/proc/self/pagemap"
#define    PFN_MASK          ((((uint64_t)1)<<55)-1)
#define    PFN_PRESENT_FLAG  (((uint64_t)1)<<63)
 
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
{
    int fd;
    int page_size = getpagesize();
    unsigned long vir_page_idx = vir / page_size;
    unsigned long pfn_item_offset = vir_page_idx * sizeof(uint64_t);
    uint64_t pfn_item;

    fd = open(page_map_file, O_RDONLY);
    if (fd < 0)
    {
        fprintf(stderr, "open %s failed", page_map_file);
        return -1;
    }

    if ((off_t) - 1 == lseek(fd, pfn_item_offset, SEEK_SET))
    {
        fprintf(stderr, "lseek %s failed", page_map_file);
        return -1;
    }

    if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
    {
        fprintf(stderr, "read %s failed", page_map_file);
        return -1;
    }

    if (0 == (pfn_item & PFN_PRESENT_FLAG))
    {
        fprintf(stderr, "page is not present");
        return -1;
    }
    *phy = (pfn_item & PFN_MASK) * page_size + vir % page_size;

    return 0;

}

fbmap.h

/*
 *  fb矩阵输出
 */
#ifndef _FBMAP_H_
#define _FBMAP_H_
#include 

//指定fb设备
#define FB_PATH "/dev/fb0"

//屏幕宽高(调用一次fb_output之后更新)
extern int fb_width, fb_height;
/*
 *  屏幕输出
 *  data: 图像数组,数据长度必须为 width*height*3, RGB格式
 *  offsetX, offsetY: 屏幕起始位置
 *  width, height: 图像宽高
 */
void fb_output(uint8_t *data, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height);
#endif

fbmap.c

/*
 *  fb矩阵输出
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "fbmap.h"

typedef struct
{
    int fd;
    unsigned char *fb;
    size_t fbSize;
    struct fb_var_screeninfo fbInfo;
    //bytes per point
    int bpp;
    //bytes width, height
    int bw, bh;
} FbMap;

static FbMap *fbmap = NULL;
int fb_width = 1024, fb_height = 600;

void fb_release(void)
{
    if (!fbmap)
        return;
    if (fbmap->fb)
        munmap(fbmap->fb, fbmap->fbSize);
    if (fbmap->fd > 0)
        close(fbmap->fd);
    free(fbmap);
    fbmap = NULL;
}
//返回0正常
int fb_init(void)
{
    if (fbmap)
        return 0;

    fbmap = (FbMap *)calloc(1, sizeof(FbMap));

    fbmap->fd = open(FB_PATH, O_RDWR);
    if (fbmap->fd < 1)
    {
        fprintf(stderr, "fb_init: open %s err \r\n", FB_PATH);
        fb_release();
        return -1;
    }

    if (ioctl(fbmap->fd, FBIOGET_VSCREENINFO, &fbmap->fbInfo) < 0)
    {
        fprintf(stderr, "fb_init: ioctl FBIOGET_VSCREENINFO err \r\n");
        fb_release();
        return -1;
    }
    printf("frameBuffer: %s, %d x %d, %dbytes / %dbpp\r\n",
            FB_PATH, fbmap->fbInfo.xres, fbmap->fbInfo.yres, fbmap->fbInfo.bits_per_pixel / 8, fbmap->fbInfo.bits_per_pixel);

    fbmap->bpp = fbmap->fbInfo.bits_per_pixel / 8;
    fbmap->bw = fbmap->bpp * fbmap->fbInfo.xres;
    fbmap->bh = fbmap->bpp * fbmap->fbInfo.yres;
    fbmap->fbSize = fbmap->fbInfo.xres * fbmap->fbInfo.yres * fbmap->bpp;

    fb_width = fbmap->fbInfo.xres;
    fb_height = fbmap->fbInfo.yres;

    fbmap->fb = (unsigned char *)mmap(0, fbmap->fbSize, PROT_READ | PROT_WRITE, MAP_SHARED, fbmap->fd, 0);
    if (!fbmap->fb)
    {
        fprintf(stderr, "fb_init: mmap size %ld err \r\n", fbmap->fbSize);
        fb_release();
        return -1;
    }

    int mem_addr_vir2phy(unsigned long vir, unsigned long *phy);
    unsigned long phy;
    *(fbmap->fb) = 0;
    mem_addr_vir2phy((long)fbmap->fb, &phy);fprintf(stderr, "mmap vir:0x%lx, phy: 0x%lx \n", (long)fbmap->fb, (long)phy);
    memset(fbmap->fb, 0, fbmap->fbSize);

    return 0;
}
/*
 *  屏幕输出
 *  data: 图像数组,数据长度必须为 width*height*3, RGB格式
 *  offsetX, offsetY: 屏幕起始位置
 *  width, height: 图像宽高
 */
void fb_output(uint8_t *data, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height)
{
    int x, y, offset;
    //初始化检查
    if (fb_init())
        return;
    //参数检查
    if (!data || width < 1 || height < 1)
        return;
    //起始坐标限制
    if (offsetX < 0)
        offsetX = 0;
    else if (offsetX >= fbmap->fbInfo.xres)
        return;
    if (offsetY < 0)
        offsetY = 0;
    else if (offsetY >= fbmap->fbInfo.yres)
        return;
    //范围限制
    if (width < 1)
        return;
    else if (offsetX + width - 1 >= fbmap->fbInfo.xres)
        width = fbmap->fbInfo.xres - offsetX;
    if (height < 1)
        return;
    else if (offsetY + height - 1 >= fbmap->fbInfo.yres)
        height = fbmap->fbInfo.yres - offsetY;
    //覆盖画图
    for (y = 0; y < height; y++)
    {
        //当前行在fb数据的偏移
        offset = (y + offsetY) * fbmap->bw + (0 + offsetX) * fbmap->bpp;
        //画data中的一行数据
        for (x = 0; x < width; x++)
        {
            if (fbmap->bpp == 4)
                fbmap->fb[offset + 3] = 0xFF; //A
            fbmap->fb[offset + 2] = *data++;  //R
            fbmap->fb[offset + 1] = *data++;  //G
            fbmap->fb[offset + 0] = *data++;  //B
            offset += fbmap->bpp;
        }
    }
}

main.c

#include 
#include 
#include 

#include "fbmap.h"

#define WIDTH 800
#define HEIGHT 600

// 设置颜色
void set(uint8_t *map, uint32_t mapSize, uint32_t rgbColor)
{
    uint32_t offset;
    uint8_t r = (rgbColor >> 16) & 0xFF;
    uint8_t g = (rgbColor >> 8) & 0xFF;
    uint8_t b = (rgbColor >> 0) & 0xFF;
    for (offset = 0; offset < mapSize;)
    {
        map[offset++] = r;
        map[offset++] = g;
        map[offset++] = b;
    }
}

int main(void)
{
        uint8_t rgbMap[WIDTH * HEIGHT * 3];
        while(1)
        {
                set(rgbMap, sizeof(rgbMap), 0xFF0000);//红
                fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
                sleep(1);

        getchar();
                set(rgbMap, sizeof(rgbMap), 0x00FF00);//绿
                fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
                sleep(1);

                set(rgbMap, sizeof(rgbMap), 0x0000FF);//蓝
                fb_output(rgbMap, 0, 0, WIDTH, HEIGHT);
                sleep(1);
        }
    return 0;
}

编译:

gcc -o out main.c fbmap.c vir2phy.c

执行

sudo ./out 

frameBuffer: /dev/fb0, 800 x 600, 4bytes / 32bpp
mmap vir:0x7efd54029000, phy: 0x3630b000 

pagemap方式,ubuntu虚拟机可以获取到fb0物理地址(开机后framebuf对应的物理地址是固定不变的,但每次开机物理地址不一样),海思平台获取不到fb0物理地址?

海思HI3531DV200获取fb物理地址方式(ubuntu虚拟机获取不到):

struct fb_fix_screeninfo fb_fix;
if(ioctl(fbmap->fd, FBIOGET_FSCREENINFO, &fb_fix) < 0)
{
     printf("ioctl FBIOGET_FSCREENINFO err\n");
     return -1;
}
printf("fb phy addr:0x%0x\n", (int)fb_fix.smem_start);

fb phy addr:0x600e5000(每次开机地址固定)

你可能感兴趣的:(linux,运维)