~ubuntu-branches/debian/stretch/uswsusp/stretch

« back to all changes in this revision

Viewing changes to vbetool/vbetool.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Perrier
  • Date: 2008-08-20 09:09:13 UTC
  • mfrom: (0.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080820090913-0eahue1zo8egcxls
Tags: 0.8-1.1
* Non-maintainer upload to fix pending l10n issues.
* Remove extra and useless debian/po/ff/ directory
* Debconf translation updates:
  - Japanese. Closes: #489939
  - German. Closes: #493747
  - French. Closes: #493771
  - Romanian. Closes: #493772
  - Galician. Closes: #494050
  - Finnish. Closes: #494087
  - Italian. Closes: #494096
  - Basque. Closes: #494277
  - Basque. Closes: #494277
  - Czech. Closes: #494410
  - Swedish. Closes: #494412
  - Russian. Closes: #495412
  - Portuguese. Closes: #495451
  - Spanish. Closes: #495499
  - Slovak. Closes: #495516

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Run video BIOS code for various purposes
 
3
 
 
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
 
6
 
 
7
This program is released under the terms of the GNU General Public License,
 
8
version 2
 
9
*/
 
10
 
 
11
#include <pci/pci.h>
 
12
#include <assert.h>
 
13
#include <stdio.h>
 
14
#include <stdlib.h>
 
15
#include <string.h>
 
16
#include <unistd.h>
 
17
#include <sys/ioctl.h>
 
18
#include <sys/types.h>
 
19
#include <sys/io.h>
 
20
#include <sys/kd.h>
 
21
#include <sys/stat.h>
 
22
#include <errno.h>
 
23
 
 
24
#include <libx86.h>
 
25
#include "vbetool.h"
 
26
 
 
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)
 
30
 
 
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
 
36
 
 
37
static struct pci_access *pacc;
 
38
 
 
39
void vbetool_init(void)
 
40
{
 
41
        if (!LRMI_init()) {
 
42
                fprintf(stderr, "Failed to initialise LRMI (Linux Real-Mode Interface).\n");
 
43
                exit(1);
 
44
        }
 
45
 
 
46
        ioperm(0, 1024, 1);
 
47
        iopl(3);
 
48
 
 
49
        pacc = pci_alloc();
 
50
        pacc->numeric_ids = 1;
 
51
        pci_init(pacc);
 
52
}
 
53
 
 
54
#ifndef S2RAM
 
55
int main(int argc, char *argv[])
 
56
{
 
57
        /* Don't bother checking for privilege if they only want usage() */
 
58
        if (argc < 2)
 
59
                goto usage;
 
60
        
 
61
        vbetool_init();
 
62
        
 
63
        if (!strcmp(argv[1], "vbestate")) {
 
64
                /* VBE save/restore tends to break when done underneath X */
 
65
                int err = check_console();
 
66
 
 
67
                if (err) {
 
68
                        return err;
 
69
                }
 
70
 
 
71
                if (!strcmp(argv[2], "save")) {
 
72
                        save_state();
 
73
                } else if (!strcmp(argv[2], "restore")) {
 
74
                        restore_state();
 
75
                } else {
 
76
                        goto usage;
 
77
                }
 
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);
 
89
                } else {
 
90
                        goto usage;
 
91
                }
 
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")) {
 
96
                        return do_get_mode();
 
97
                } else {
 
98
                        goto usage;
 
99
                }
 
100
        } else if (!strcmp(argv[1], "vgamode")) {
 
101
                if (!strcmp(argv[2], "set")) {
 
102
                        return do_set_mode(atoi(argv[3]),1);
 
103
                } else {
 
104
                        return do_set_mode(atoi(argv[2]),1);
 
105
                }
 
106
        } else if (!strcmp(argv[1], "post")) {
 
107
                /* Again, we don't really want to do this while X is in 
 
108
                   control */
 
109
                int err = check_console();
 
110
 
 
111
                if (err) {
 
112
                        return err;
 
113
                }
 
114
 
 
115
                return do_post();
 
116
        } else if (!strcmp(argv[1], "vgastate")) {
 
117
                if (!strcmp(argv[2], "on")) {
 
118
                        return enable_vga();
 
119
                } else {
 
120
                        return disable_vga();
 
121
                }
 
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();
 
133
                } else {
 
134
                        return 1;
 
135
                }
 
136
        } else {
 
137
              usage:
 
138
                fprintf(stderr,
 
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",
 
140
                        argv[0], argv[0]);
 
141
                return 1;
 
142
        }
 
143
 
 
144
        return 0;
 
145
}
 
146
#endif
 
147
 
 
148
int do_vbe_service(unsigned int AX, unsigned int BX, reg_frame * regs)
 
149
{
 
150
        const unsigned interrupt = 0x10;
 
151
        unsigned function_sup;
 
152
        unsigned success;
 
153
        regs->ds = 0x0040;
 
154
 
 
155
        access_ptr_register(regs, eax) = AX;
 
156
        access_ptr_register(regs, ebx) = BX;
 
157
 
 
158
        if (real_mode_int(interrupt, regs)) {
 
159
                fprintf(stderr,
 
160
                        "Error: something went wrong performing real mode interrupt\n");
 
161
                return -1;
 
162
        }
 
163
 
 
164
        AX = access_ptr_register(regs, eax);
 
165
 
 
166
        function_sup = ((AX & 0xff) == 0x4f);
 
167
        success = ((AX & 0xff00) == 0);
 
168
 
 
169
        if (!success) {
 
170
                fprintf(stderr, "Real mode call failed\n");
 
171
                return -2;
 
172
        }
 
173
 
 
174
        if (!function_sup) {
 
175
                fprintf(stderr, "Function not supported?\n");
 
176
                return -3;
 
177
        }
 
178
 
 
179
        return access_ptr_register(regs, ebx);
 
180
}
 
181
 
 
182
int do_real_post(unsigned pci_device)
 
183
{
 
184
        int error = 0;
 
185
        struct LRMI_regs r;
 
186
        memset(&r, 0, sizeof(r));
 
187
 
 
188
        /* Several machines seem to want the device that they're POSTing in
 
189
           here */
 
190
        r.eax = pci_device;
 
191
 
 
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 */
 
194
        r.cs = 0xc000;
 
195
        r.ip = 0x0003;
 
196
 
 
197
        /* This is all heavily cargo culted but seems to work */
 
198
        r.edx = 0x80;
 
199
        r.ds = 0x0040;
 
200
 
 
201
        if (!LRMI_call(&r)) {
 
202
                fprintf(stderr,
 
203
                        "Error: something went wrong performing real mode call\n");
 
204
                error = 1;
 
205
        }
 
206
 
 
207
        return error;
 
208
}
 
209
 
 
210
int do_post(void)
 
211
{
 
212
        struct pci_dev *p;
 
213
        unsigned int c;
 
214
        unsigned int pci_id;
 
215
        int error;
 
216
 
 
217
        pci_scan_bus(pacc);
 
218
 
 
219
        for (p = pacc->devices; p; p = p->next) {
 
220
                c = pci_read_word(p, PCI_CLASS_DEVICE);
 
221
                if (c == 0x300) {
 
222
                        pci_id =
 
223
                            (p->bus << 8) + (p->dev << 3) +
 
224
                            (p->func & 0x7);
 
225
                        error = do_real_post(pci_id);
 
226
                        if (error != 0) {
 
227
                                return error;
 
228
                        }
 
229
                }
 
230
        }
 
231
        return 0;
 
232
}
 
233
 
 
234
void restore_state_from(char *data)
 
235
{
 
236
        struct LRMI_regs r;
 
237
 
 
238
        /* VGA BIOS mode 3 is text mode */
 
239
        do_set_mode(3,1);
 
240
 
 
241
        memset(&r, 0, sizeof(r));
 
242
 
 
243
        r.eax = 0x4f04;
 
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;
 
248
        r.ds = 0x0040;
 
249
 
 
250
        if (!LRMI_int(0x10, &r)) {
 
251
                fprintf(stderr,
 
252
                        "Can't restore video state (vm86 failure)\n");
 
253
        } else if ((r.eax & 0xffff) != 0x4f) {
 
254
                fprintf(stderr, "Restore video state failed\n");
 
255
        }
 
256
 
 
257
        LRMI_free_real(data);
 
258
 
 
259
        ioctl(0, KDSETMODE, KD_TEXT);
 
260
 
 
261
}
 
262
 
 
263
void restore_state(void)
 
264
{
 
265
 
 
266
        char *data = NULL;
 
267
        char tmpbuffer[524288];
 
268
        int i, length = 0;
 
269
 
 
270
        /* We really, really don't want to fail to read the entire set */
 
271
        while ((i = read(0, tmpbuffer + length, sizeof(tmpbuffer)-length))) {
 
272
                if (i == -1) {
 
273
                        if (errno != EAGAIN && errno != EINTR) {
 
274
                                perror("Failed to read state - ");
 
275
                                return;
 
276
                        }
 
277
                } else {
 
278
                        length += i;
 
279
                }
 
280
        }
 
281
 
 
282
        data = LRMI_alloc_real(length);
 
283
        memcpy(data, tmpbuffer, length);
 
284
 
 
285
        restore_state_from(data);
 
286
}
 
287
 
 
288
char *__save_state(int *psize)
 
289
{
 
290
        struct LRMI_regs r;
 
291
        char *buffer;
 
292
        unsigned int size;
 
293
 
 
294
        memset(&r, 0, sizeof(r));
 
295
 
 
296
        r.eax = 0x4f04;
 
297
        r.ecx = 0xf;            /* all states */
 
298
        r.edx = 0;              /* get buffer size */
 
299
        r.ds = 0x0040;
 
300
 
 
301
        if (!LRMI_int(0x10, &r)) {
 
302
                fprintf(stderr,
 
303
                        "Can't get video state buffer size (vm86 failure)\n");
 
304
        }
 
305
 
 
306
        if ((r.eax & 0xffff) != 0x4f) {
 
307
                fprintf(stderr, "Get video state buffer size failed\n");
 
308
        }
 
309
 
 
310
        *psize = size = (r.ebx & 0xffff) * 64;
 
311
 
 
312
        buffer = LRMI_alloc_real(size);
 
313
 
 
314
        if (buffer == NULL) {
 
315
                fprintf(stderr, "Can't allocate video state buffer\n");
 
316
                return NULL;
 
317
        }
 
318
 
 
319
        memset(&r, 0, sizeof(r));
 
320
 
 
321
        fprintf(stderr, "Allocated buffer at %p (base is 0x%x)\n", buffer,
 
322
                        LRMI_base_addr());
 
323
 
 
324
        r.eax = 0x4f04;
 
325
        r.ecx = 0xf;            /* all states */
 
326
        r.edx = 1;              /* save state */
 
327
        
 
328
        r.es = (unsigned int) (buffer - LRMI_base_addr()) >> 4;
 
329
        r.ebx = (unsigned int) (buffer - LRMI_base_addr()) & 0xf;
 
330
        r.ds = 0x0040;
 
331
 
 
332
        fprintf(stderr, "ES: 0x%04X EBX: 0x%04X\n", r.es, r.ebx);
 
333
 
 
334
        if (!LRMI_int(0x10, &r)) {
 
335
                fprintf(stderr, "Can't save video state (vm86 failure)\n");
 
336
        }
 
337
 
 
338
        if ((r.eax & 0xffff) != 0x4f) {
 
339
                fprintf(stderr, "Save video state failed\n");
 
340
        }
 
341
        return buffer;
 
342
}
 
343
 
 
344
void save_state(void)
 
345
{
 
346
        int size;
 
347
        char *buffer = __save_state(&size);
 
348
 
 
349
        if (buffer)
 
350
                write(1, buffer, size); /* FIXME: should retry on short write); */
 
351
}
 
352
 
 
353
int do_blank(int state)
 
354
{
 
355
        reg_frame regs;
 
356
        int error;
 
357
 
 
358
        memset(&regs, 0, sizeof(regs));
 
359
        error = do_vbe_service(0x4f10, state |= 0x01, &regs);
 
360
        if (error<0) {
 
361
                return error;
 
362
        }
 
363
        return 0;
 
364
}
 
365
 
 
366
int do_set_mode (int mode, int vga) {
 
367
        reg_frame regs;
 
368
        int error;
 
369
 
 
370
        memset(&regs, 0, sizeof(regs));
 
371
 
 
372
        if (vga) {
 
373
                error = do_vbe_service(mode, 0, &regs);
 
374
        } else {
 
375
                error = do_vbe_service(0x4f02, mode, &regs);
 
376
        }
 
377
 
 
378
        if (error<0) {
 
379
                return error;
 
380
        }
 
381
        
 
382
        return 0;
 
383
}
 
384
 
 
385
int do_get_panel_brightness() {
 
386
        reg_frame regs;
 
387
        int error;
 
388
 
 
389
        memset(&regs, 0, sizeof(regs));
 
390
 
 
391
        error = do_vbe_service(0x4f11, 0x05, &regs);
 
392
 
 
393
        if (error<0) {
 
394
                return error;
 
395
        }
 
396
 
 
397
        printf("%d\n",regs.ecx);
 
398
 
 
399
        return 0;
 
400
}
 
401
 
 
402
int do_invert_panel() {
 
403
        reg_frame regs;
 
404
        int error;
 
405
 
 
406
        memset(&regs, 0, sizeof(regs));
 
407
 
 
408
        error = do_vbe_service(0x4f11, 0x02, &regs);
 
409
 
 
410
        if (error<0) {
 
411
                return error;
 
412
        }
 
413
 
 
414
        if ((regs.ebx & 0xff) == 0)
 
415
                regs.ecx = 3;
 
416
        else
 
417
                regs.ecx = 0;
 
418
 
 
419
        error = do_vbe_service(0x4f11, 0x0102, &regs);
 
420
 
 
421
        if (error<0) {
 
422
                return error;
 
423
        }
 
424
 
 
425
        return 0;
 
426
}
 
427
 
 
428
int do_set_panel_brightness(int brightness) {
 
429
        reg_frame regs;
 
430
        int error;
 
431
 
 
432
        memset(&regs, 0, sizeof(regs));
 
433
 
 
434
        regs.ecx = brightness;
 
435
 
 
436
        error = do_vbe_service(0x4f11, 0x0105, &regs);
 
437
 
 
438
        if (error<0) {
 
439
                return error;
 
440
        }
 
441
 
 
442
        printf("%d\n",regs.ecx);
 
443
 
 
444
        return 0;
 
445
}
 
446
 
 
447
int __get_mode()
 
448
{
 
449
        reg_frame regs;
 
450
        int error;
 
451
 
 
452
        memset(&regs, 0, sizeof(regs));
 
453
        error = do_vbe_service(0x4f03, 0, &regs);
 
454
        return error;
 
455
}
 
456
 
 
457
int do_get_mode() {
 
458
        int error = __get_mode();
 
459
 
 
460
        if (error<0) {
 
461
                return error;
 
462
        }
 
463
        
 
464
        printf("%d\n",error);
 
465
        return 0;
 
466
}
 
467
 
 
468
int check_console()
 
469
{
 
470
        struct stat stat;
 
471
 
 
472
        return 0;
 
473
 
 
474
        if (fstat(0, &stat) != 0) {
 
475
                fprintf(stderr, "Can't stat() stdin\n");
 
476
                return 10;
 
477
        }
 
478
 
 
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");
 
482
                return 11;
 
483
        }
 
484
 
 
485
        ioctl(0, KDSETMODE, KD_GRAPHICS);
 
486
        return 0;
 
487
}
 
488
 
 
489
int enable_vga() {
 
490
        outb(0x03 | inb(0x3CC),  0x3C2);
 
491
        outb(0x01 | inb(0x3C3),  0x3C3);
 
492
        outb(0x08 | inb(0x46e8), 0x46e8);
 
493
        outb(0x01 | inb(0x102),  0x102);
 
494
        return 0;
 
495
}
 
496
 
 
497
int disable_vga() {
 
498
        outb(~0x03 & inb(0x3CC),  0x3C2);
 
499
        outb(~0x01 & inb(0x3C3),  0x3C3);
 
500
        outb(~0x08 & inb(0x46e8), 0x46e8);
 
501
        outb(~0x01 & inb(0x102),  0x102);
 
502
        return 0;
 
503
}
 
504
 
 
505
/* Based on xserver-xorg-driver-i810/src/i830_driver.c */
 
506
struct panel_id {
 
507
  int hsize:16, vsize:16;
 
508
  int fptype:16;
 
509
  int redbpp:8, greenbpp:8, bluebpp:8, reservedbpp:8;
 
510
  int rsvdoffscrnmemsize:32, rsvdoffscrnmemptr:32;
 
511
  char reserved[14];
 
512
} __attribute__((packed));
 
513
 
 
514
int do_get_panel_id(int just_dimensions)
 
515
{
 
516
  reg_frame r = {
 
517
    .eax = 0x4f11,
 
518
    .ebx = 0x0001
 
519
  };
 
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;
 
523
 
 
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;
 
526
 
 
527
  if(real_mode_int(0x10, &r))
 
528
    return fprintf(stderr, "Can't get panel id (vm86 failure)\n"), 8;
 
529
 
 
530
  if((r.eax & 0xff) != 0x4f)
 
531
    return fprintf(stderr, "Panel id function not supported\n"), 9;
 
532
 
 
533
  if(r.eax & 0xff00)
 
534
    {
 
535
      if((r.eax & 0xff00) == 0x100)
 
536
        fprintf(stderr, "Panel id read failed\n");
 
537
      else
 
538
        fprintf(stderr, "Panel id function not successful\n");
 
539
      return 10;
 
540
    }
 
541
 
 
542
  if(!just_dimensions)
 
543
    printf("size:\t%d %d\n"
 
544
           "type:\t%d\n"
 
545
           "bpp:\t%d %d %d %d\n",
 
546
           id->hsize, id->vsize,
 
547
           id->fptype,
 
548
           id->redbpp, id->greenbpp, id->bluebpp, id->reservedbpp);
 
549
  else
 
550
    printf("%dx%d\n", id->hsize, id->vsize);
 
551
 
 
552
#if 0
 
553
 
 
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.
 
557
   */
 
558
  printf("ram:\t%dkB\n"
 
559
         "offset:\t%p\n",
 
560
         id->rsvdoffscrnmemsize,
 
561
         (void *)id->rsvdoffscrnmemptr);
 
562
#endif
 
563
 
 
564
  return 0;
 
565
}