Цветовая карта wsdisplay не получается правильно
Я пытался использовать wscons
а также wsdisplay
на NetBSD 5.1.2 (с использованием реализации кадрового буфера VESA) недавно, и я столкнулся с небольшой проблемой:
Я могу установить карты цветов успешно, и они выглядят правильно, но получение карт цветов, похоже, возвращает неверные данные, так что, когда я пытаюсь восстановить исходную карту цветов после завершения программы, все цвета неверны:
Вот сокращенная программа, вызывающая проблему (обратите внимание, что она должна быть запущена как 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 ответ
причина
Я больше разбирался в проблеме, и оказалось, что некоторая память ядра либо неинициализирована, либо повреждена. В частности, sc_cmap_red
, sc_cmap_green
, а также sc_cmap_blue
из struct vesafb_softc
(в vesafbvar.h
в строках с 89 по 91) содержат неверные данные. Это несколько удивительно, так как строки с 719 по 722 vesafb.c
инициализировать его:
/* 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_cmap
который определяется по строкам с 55 по 122 в rasops.c
:
/* ANSI colormap (R,G,B). Upper 8 are high-intensity */
const u_char rasops_cmap[256*3] = {
/* ... */
};
С этими цветами вы можете создать программу, которая устанавливает это в качестве текущей карты цветов. Мне пришлось сделать несколько изменений, чтобы курсор не исчез, но в основном он работал.
Лучшее решение
Поскольку я искал больше информации, я нашел этот пост в блоге. Когда я перекомпилировал ядро с genfb(4)
скорее, чем vesafb(4)
, ядро зависало при загрузке. Оказывается, это потому, что используемый мной загрузчик не был достаточно новым для передачи необходимых параметров ядру.
Я случайно посмотрел журнал изменений NetBSD 6.0 и заметил эту запись:
- amd64, i386
Загрузчик был улучшен для поддержки консолей кадрового буфера с использованием расширений VESA BIOS. Эти изменения позволяют портам x86 работать с драйвером genfb(4) и устаревать драйвер vesafb(4) только для i386. [jmcneill 20090216]
Я скачал NetBSD 6.0_BETA и загрузил его из приглашения на загрузку следующим образом:
> vesa 640x480x8
> boot netbsd
... и все заработало.