未正确检索wsdisplay颜色映射

时间:2012-03-31 04:15:43

标签: c color-palette netbsd

我最近一直试图在NetBSD 5.1.2上使用wsconswsdisplay(使用VESA帧缓冲实现),我遇到了一些问题:

我可以成功设置色彩映射并且它们看起来正确但 获取色彩映射似乎返回不正确的数据,这样当我尝试程序完成后,恢复原始颜色映射,所有颜色都不正确:

Vim, showing the program's source with a strange color map

这是导致问题的简化程序(请注意,它必须以root或用户登录第二个虚拟终端(/dev/ttyE1)运行:

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <dev/wscons/wsconsio.h>

int main(int argc, char **argv) {
    (void)argc, (void)argv;
    int tty = open("/dev/ttyE1", O_RDWR | O_EXCL);
    if(tty == -1) {
        perror("error opening tty");
        return EXIT_FAILURE;
    }
    struct wsdisplay_fbinfo fbinfo;
    if(ioctl(tty, WSDISPLAYIO_GINFO, &fbinfo) == -1) {
        perror("error retrieving framebuffer info");
        close(tty);
        return EXIT_FAILURE;
    }
    uint8_t *cmap_data = malloc(fbinfo.cmsize * 3);
    if(cmap_data == NULL) {
        perror("error allocating memory for color map data");
        close(tty);
        return EXIT_FAILURE;
    }
    struct wsdisplay_cmap cmap;
    cmap.index = 0;
    cmap.count = fbinfo.cmsize;
    cmap.red   = &cmap_data[fbinfo.cmsize * 0];
    cmap.green = &cmap_data[fbinfo.cmsize * 1];
    cmap.blue  = &cmap_data[fbinfo.cmsize * 2];
    if(ioctl(tty, WSDISPLAYIO_GETCMAP, &cmap) == -1) {
        perror("error getting color map");
        close(tty), free(cmap_data);
        return EXIT_FAILURE;
    }
    if(ioctl(tty, WSDISPLAYIO_PUTCMAP, &cmap) == -1) {
        perror("error putting color map");
        close(tty), free(cmap_data);
        return EXIT_FAILURE;
    }
    free(cmap_data);
    close(tty);
    return EXIT_SUCCESS;
}

我做错了什么,如何才能正确检索和恢复彩色地图?

1 个答案:

答案 0 :(得分:0)

原因

我更多地研究了这个问题,似乎某些内核内存未初始化或被破坏。具体而言,sc_cmap_red的{​​{1}},sc_cmap_greensc_cmap_blue(在第89到91行的vesafbvar.h中)包含不正确的数据。这有点令人惊讶,因为vesafb.c的第719行到第722行初始化它:

struct vesafb_softc

它包含不正确的数据,即使我将其移出/* Fill in the softc colourmap arrays */ sc->sc_cmap_red[i / 3] = rasops_cmap[i + 0]; sc->sc_cmap_green[i / 3] = rasops_cmap[i + 1]; sc->sc_cmap_blue[i / 3] = rasops_cmap[i + 2]; 语句,因此它可能会被破坏而不是未初始化。

驱动程序 能够正确获取和设置颜色映射;它似乎无法在if中获得最初的那个。

解决方法

一个简单的解决方案是让程序重新设置默认的颜色映射。如上面的代码段所示,假设struct vesafb_softc获取其初始颜色,恰好在rasops.c的第55到122行定义:

rasops_cmap

使用这些颜色,您可以创建一个程序,将其设置为当前颜色映射。我不得不进行一些更改,因此光标不会消失,但它大部分都有效。

更好的解决方案

当我四处寻找更多信息时,我找到了this blog post。当我用genfb(4)而不是vesafb(4)重新编译内核时,内核在启动时挂起。事实证明这是因为我使用的引导加载程序不够新,无法将所需的参数传递给内核。

我碰巧看了NetBSD 6.0 changelog并注意到了这个条目:

  
      
  • amd64i386
      引导加载程序已得到增强,可使用VESA BIOS扩展支持帧缓冲控制台。这些更改允许x86端口与genfb(4)驱动程序一起使用,并废弃仅支持i386的vesafb(4)驱动程序。 [jmcneill 20090216]
  •   

我下载了NetBSD 6.0_BETA并从启动提示符启动它,如下所示:

/* ANSI colormap (R,G,B). Upper 8 are high-intensity */
const u_char rasops_cmap[256*3] = {
    /* ... */
};

......一切正常。

简而言之,使用较新版本的NetBSD并放弃vesafb(4)可以解决问题。