2
Run video BIOS code for various purposes
4
Copyright Matthew Garrett <mjg59@srcf.ucam.org>, heavily based on
5
vbetest.c from the lrmi package and read-edid.c by John Fremlin
7
This program is released under the terms of the GNU General Public License,
17
#include <sys/ioctl.h>
18
#include <sys/types.h>
27
#define access_ptr_register(reg_frame,reg) (reg_frame -> reg)
28
#define access_seg_register(reg_frame,es) reg_frame.es
29
#define real_mode_int(interrupt,reg_frame_ptr) !LRMI_int(interrupt,reg_frame_ptr)
31
#define DPMS_STATE_ON 0x0000
32
#define DPMS_STATE_STANDBY 0x0100
33
#define DPMS_STATE_SUSPEND 0x0200
34
#define DPMS_STATE_OFF 0x0400
35
#define DPMS_STATE_LOW 0x0800
37
static struct pci_access *pacc;
39
void vbetool_init(void)
42
fprintf(stderr, "Failed to initialise LRMI (Linux Real-Mode Interface).\n");
50
pacc->numeric_ids = 1;
55
int main(int argc, char *argv[])
57
/* Don't bother checking for privilege if they only want usage() */
63
if (!strcmp(argv[1], "vbestate")) {
64
/* VBE save/restore tends to break when done underneath X */
65
int err = check_console();
71
if (!strcmp(argv[2], "save")) {
73
} else if (!strcmp(argv[2], "restore")) {
78
} else if (!strcmp(argv[1], "dpms")) {
79
if (!strcmp(argv[2], "on")) {
80
return do_blank(DPMS_STATE_ON);
81
} else if (!strcmp(argv[2], "suspend")) {
82
return do_blank(DPMS_STATE_SUSPEND);
83
} else if (!strcmp(argv[2], "standby")) {
84
return do_blank(DPMS_STATE_STANDBY);
85
} else if (!strcmp(argv[2], "off")) {
86
return do_blank(DPMS_STATE_OFF);
87
} else if (!strcmp(argv[2], "reduced")) {
88
return do_blank(DPMS_STATE_LOW);
92
} else if (!strcmp(argv[1], "vbemode")) {
93
if (!strcmp(argv[2], "set")) {
94
return do_set_mode(atoi(argv[3]),0);
95
} else if (!strcmp(argv[2], "get")) {
100
} else if (!strcmp(argv[1], "vgamode")) {
101
if (!strcmp(argv[2], "set")) {
102
return do_set_mode(atoi(argv[3]),1);
104
return do_set_mode(atoi(argv[2]),1);
106
} else if (!strcmp(argv[1], "post")) {
107
/* Again, we don't really want to do this while X is in
109
int err = check_console();
116
} else if (!strcmp(argv[1], "vgastate")) {
117
if (!strcmp(argv[2], "on")) {
120
return disable_vga();
122
} else if (!strcmp(argv[1], "vbefp")) {
123
if (!strcmp(argv[2], "id") || !strcmp(argv[2], "panelid")) {
124
return do_get_panel_id(0);
125
} else if (!strcmp(argv[2], "panelsize")) {
126
return do_get_panel_id(1);
127
} else if (!strcmp(argv[2], "getbrightness")) {
128
return do_get_panel_brightness();
129
} else if (!strcmp(argv[2], "setbrightness")) {
130
return do_set_panel_brightness(atoi(argv[3]));
131
} else if (!strcmp(argv[2], "invert")) {
132
return do_invert_panel();
139
"%s: Usage %s [[vbestate save|restore]|[vbemode set|get]|[vgamode]|[dpms on|off|standby|suspend|reduced]|[post]|[vgastate on|off]|[vbefp panelid|panelsize|getbrightness|setbrightness|invert]]\n",
148
int do_vbe_service(unsigned int AX, unsigned int BX, reg_frame * regs)
150
const unsigned interrupt = 0x10;
151
unsigned function_sup;
155
access_ptr_register(regs, eax) = AX;
156
access_ptr_register(regs, ebx) = BX;
158
if (real_mode_int(interrupt, regs)) {
160
"Error: something went wrong performing real mode interrupt\n");
164
AX = access_ptr_register(regs, eax);
166
function_sup = ((AX & 0xff) == 0x4f);
167
success = ((AX & 0xff00) == 0);
170
fprintf(stderr, "Real mode call failed\n");
175
fprintf(stderr, "Function not supported?\n");
179
return access_ptr_register(regs, ebx);
182
int do_real_post(unsigned pci_device)
186
memset(&r, 0, sizeof(r));
188
/* Several machines seem to want the device that they're POSTing in
192
/* 0xc000 is the video option ROM. The init code for each
193
option ROM is at 0x0003 - so jump to c000:0003 and start running */
197
/* This is all heavily cargo culted but seems to work */
201
if (!LRMI_call(&r)) {
203
"Error: something went wrong performing real mode call\n");
219
for (p = pacc->devices; p; p = p->next) {
220
c = pci_read_word(p, PCI_CLASS_DEVICE);
223
(p->bus << 8) + (p->dev << 3) +
225
error = do_real_post(pci_id);
234
void restore_state_from(char *data)
238
/* VGA BIOS mode 3 is text mode */
241
memset(&r, 0, sizeof(r));
244
r.ecx = 0xf; /* all states */
245
r.edx = 2; /* restore state */
246
r.es = (unsigned int) (data - LRMI_base_addr()) >> 4;
247
r.ebx = (unsigned int) (data - LRMI_base_addr()) & 0xf;
250
if (!LRMI_int(0x10, &r)) {
252
"Can't restore video state (vm86 failure)\n");
253
} else if ((r.eax & 0xffff) != 0x4f) {
254
fprintf(stderr, "Restore video state failed\n");
257
LRMI_free_real(data);
259
ioctl(0, KDSETMODE, KD_TEXT);
263
void restore_state(void)
267
char tmpbuffer[524288];
270
/* We really, really don't want to fail to read the entire set */
271
while ((i = read(0, tmpbuffer + length, sizeof(tmpbuffer)-length))) {
273
if (errno != EAGAIN && errno != EINTR) {
274
perror("Failed to read state - ");
282
data = LRMI_alloc_real(length);
283
memcpy(data, tmpbuffer, length);
285
restore_state_from(data);
288
char *__save_state(int *psize)
294
memset(&r, 0, sizeof(r));
297
r.ecx = 0xf; /* all states */
298
r.edx = 0; /* get buffer size */
301
if (!LRMI_int(0x10, &r)) {
303
"Can't get video state buffer size (vm86 failure)\n");
306
if ((r.eax & 0xffff) != 0x4f) {
307
fprintf(stderr, "Get video state buffer size failed\n");
310
*psize = size = (r.ebx & 0xffff) * 64;
312
buffer = LRMI_alloc_real(size);
314
if (buffer == NULL) {
315
fprintf(stderr, "Can't allocate video state buffer\n");
319
memset(&r, 0, sizeof(r));
321
fprintf(stderr, "Allocated buffer at %p (base is 0x%x)\n", buffer,
325
r.ecx = 0xf; /* all states */
326
r.edx = 1; /* save state */
328
r.es = (unsigned int) (buffer - LRMI_base_addr()) >> 4;
329
r.ebx = (unsigned int) (buffer - LRMI_base_addr()) & 0xf;
332
fprintf(stderr, "ES: 0x%04X EBX: 0x%04X\n", r.es, r.ebx);
334
if (!LRMI_int(0x10, &r)) {
335
fprintf(stderr, "Can't save video state (vm86 failure)\n");
338
if ((r.eax & 0xffff) != 0x4f) {
339
fprintf(stderr, "Save video state failed\n");
344
void save_state(void)
347
char *buffer = __save_state(&size);
350
write(1, buffer, size); /* FIXME: should retry on short write); */
353
int do_blank(int state)
358
memset(®s, 0, sizeof(regs));
359
error = do_vbe_service(0x4f10, state |= 0x01, ®s);
366
int do_set_mode (int mode, int vga) {
370
memset(®s, 0, sizeof(regs));
373
error = do_vbe_service(mode, 0, ®s);
375
error = do_vbe_service(0x4f02, mode, ®s);
385
int do_get_panel_brightness() {
389
memset(®s, 0, sizeof(regs));
391
error = do_vbe_service(0x4f11, 0x05, ®s);
397
printf("%d\n",regs.ecx);
402
int do_invert_panel() {
406
memset(®s, 0, sizeof(regs));
408
error = do_vbe_service(0x4f11, 0x02, ®s);
414
if ((regs.ebx & 0xff) == 0)
419
error = do_vbe_service(0x4f11, 0x0102, ®s);
428
int do_set_panel_brightness(int brightness) {
432
memset(®s, 0, sizeof(regs));
434
regs.ecx = brightness;
436
error = do_vbe_service(0x4f11, 0x0105, ®s);
442
printf("%d\n",regs.ecx);
452
memset(®s, 0, sizeof(regs));
453
error = do_vbe_service(0x4f03, 0, ®s);
458
int error = __get_mode();
464
printf("%d\n",error);
474
if (fstat(0, &stat) != 0) {
475
fprintf(stderr, "Can't stat() stdin\n");
479
if ((stat.st_rdev & 0xff00) != 0x400 || (stat.st_rdev & 0xff) > 63) {
480
fprintf(stderr, "To perform this operation, "
481
"this program must be run from the console\n");
485
ioctl(0, KDSETMODE, KD_GRAPHICS);
490
outb(0x03 | inb(0x3CC), 0x3C2);
491
outb(0x01 | inb(0x3C3), 0x3C3);
492
outb(0x08 | inb(0x46e8), 0x46e8);
493
outb(0x01 | inb(0x102), 0x102);
498
outb(~0x03 & inb(0x3CC), 0x3C2);
499
outb(~0x01 & inb(0x3C3), 0x3C3);
500
outb(~0x08 & inb(0x46e8), 0x46e8);
501
outb(~0x01 & inb(0x102), 0x102);
505
/* Based on xserver-xorg-driver-i810/src/i830_driver.c */
507
int hsize:16, vsize:16;
509
int redbpp:8, greenbpp:8, bluebpp:8, reservedbpp:8;
510
int rsvdoffscrnmemsize:32, rsvdoffscrnmemptr:32;
512
} __attribute__((packed));
514
int do_get_panel_id(int just_dimensions)
520
struct panel_id *id = LRMI_alloc_real(sizeof(struct panel_id));
521
r.es = (unsigned short)(((int)(id-LRMI_base_addr()) >> 4) & 0xffff);
522
r.edi = (unsigned long)(id-LRMI_base_addr()) & 0xf;
524
if(sizeof(struct panel_id) != 32)
525
return fprintf(stderr, "oops: panel_id, sizeof struct panel_id != 32, it's %ld...\n", sizeof(struct panel_id)), 7;
527
if(real_mode_int(0x10, &r))
528
return fprintf(stderr, "Can't get panel id (vm86 failure)\n"), 8;
530
if((r.eax & 0xff) != 0x4f)
531
return fprintf(stderr, "Panel id function not supported\n"), 9;
535
if((r.eax & 0xff00) == 0x100)
536
fprintf(stderr, "Panel id read failed\n");
538
fprintf(stderr, "Panel id function not successful\n");
543
printf("size:\t%d %d\n"
545
"bpp:\t%d %d %d %d\n",
546
id->hsize, id->vsize,
548
id->redbpp, id->greenbpp, id->bluebpp, id->reservedbpp);
550
printf("%dx%d\n", id->hsize, id->vsize);
554
/* Don't have a use for these and they don't seem to be documented.
555
* 320 appears to be 320kB of mapped memory and the following
556
* pointer is 0x1ffb8000 which is kernel mapping + 0xb8000 offset.
558
printf("ram:\t%dkB\n"
560
id->rsvdoffscrnmemsize,
561
(void *)id->rsvdoffscrnmemptr);