initial commit
[vidsys] / drv_vbe.c
1 #include <string.h>
2 #include <conio.h>
3 #include <i86.h>
4 #include "vidsys.h"
5 #include "drv.h"
6 #include "vbe.h"
7 #include "cdpmi.h"
8
9 #define farptr_to_linear(rmaddr) \
10         ((((intptr_t)(rmaddr) >> 12) & 0xffff0) + ((intptr_t)(rmaddr) & 0xffff))
11
12 static int init(void);
13 static void cleanup(void);
14 static int setmode(int mode);
15 static int getmode(void);
16 static const char *memsize_str(long sz);
17 static int get_mode_info(int mode, struct vbe_mode_info *mi);
18 static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi);
19
20 static struct vid_driver drv = {"vbe", 2};
21 static struct vid_drvops drvops = {init, cleanup, setmode, getmode};
22 static struct vid_modeinfo *modes;
23 static int num_modes;
24 static unsigned int vbe_ver;
25
26
27 void vid_register_vbe(void)
28 {
29         drv.ops = &drvops;
30
31         vid_drvlist[vid_numdrv++] = &drv;
32 }
33
34
35 static int init(void)
36 {
37         struct dpmi_regs regs = {0};
38         struct vbe_info *vbe;
39         struct vbe_mode_info vbemi;
40         unsigned short bufseg;
41         uint16_t *vbe_modelist, *modelist;
42         int i, count;
43         struct vid_modeinfo modeinf;
44
45         vbe = dpmi_lowbuf();
46         bufseg = (intptr_t)vbe >> 4;
47
48         /* call VBE function 00 (get controller information) */
49         memcpy(vbe->sig, "VBE2", 4);    /* denote we want VBE 2.0 info */
50         regs.eax = 0x4f00;
51         regs.es = bufseg;
52         dpmi_rmint(0x10, &regs);
53         if(regs.eax != 0x4f || memcmp(vbe->sig, "VESA", 4) != 0) {
54                 fprintf(stderr, "failed to get VBE controller information\n");
55                 return -1;
56         }
57
58         vbe_ver = vbe->ver;
59
60         printf("Found VBE %d.%d\n", vbe_ver >> 8, vbe_ver & 0xff);
61         printf("OEM: %s\n", (char*)farptr_to_linear(vbe->oem_name));
62         if(vbe_ver >= 0x0200) {
63                 printf("%s - %s (%s)\n", (char*)farptr_to_linear(vbe->vendor),
64                                 (char*)farptr_to_linear(vbe->product),
65                                 (char*)farptr_to_linear(vbe->revstr));
66         }
67         printf("Video RAM: %s\n", memsize_str((long)vbe->vmem_blk * 65536));
68
69         vbe_modelist = (uint16_t*)farptr_to_linear(vbe->modelist_addr);
70         count = 0;
71         for(i=0; i<1024; i++) {
72                 if(vbe_modelist[i] == 0xffff) break;
73                 count++;
74         }
75
76         if(!(modelist = malloc(count * sizeof *modelist))) {
77                 fprintf(stderr, "failed to allocate mode list\n");
78                 return -1;
79         }
80         for(i=0; i<count; i++) {
81                 modelist[i] = vbe_modelist[i];
82         }
83
84         printf("found %d modes\n", count);
85         return 0;
86         num_modes = 0;
87         for(i=0; i<count; i++) {
88                 if(get_mode_info(modelist[i], &vbemi) == -1) {
89                         continue;
90                 }
91                 conv_vbeinfo(modelist[i], modes + num_modes++, &vbemi);
92         }
93
94         return 0;
95 }
96
97 static void cleanup(void)
98 {
99 }
100
101 static int setmode(int mode)
102 {
103         return -1;
104 }
105
106 static int getmode(void)
107 {
108         return -1;
109 }
110
111 static const char *memsize_str(long sz)
112 {
113         static const char *suffix[] = {"bytes", "kb", "mb", "gb", 0};
114         static int cnt = 0;
115         static char buf[64];
116
117         while(sz > 1024 && suffix[cnt + 1]) {
118                 sz >>= 10;
119                 cnt++;
120         }
121
122         sprintf(buf, "%ld %s", sz, suffix[cnt]);
123         return buf;
124 }
125
126 static int get_mode_info(int mode, struct vbe_mode_info *mi)
127 {
128         struct dpmi_regs regs = {0};
129         struct vbe_mode_info *miptr;
130         uint16_t bufseg;
131
132         miptr = dpmi_lowbuf();
133         bufseg = (intptr_t)miptr >> 4;
134
135         regs.eax = 0x4f01;
136         regs.ecx = mode;
137         regs.es = bufseg;
138         dpmi_rmint(0x10, &regs);
139         if(regs.eax != 0x4f) {
140                 return -1;
141         }
142
143         *mi = *miptr;
144         return 0;
145 }
146
147 static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi)
148 {
149         static const struct { int width, height, bpp; } stdmode[] = {
150                 {640, 400, 8},          /* 100h */
151                 {640, 480, 8},          /* 101h */
152                 {800, 600, 4},          /* 102h */
153                 {800, 600, 8},          /* 103h */
154                 {1024, 768, 4},         /* 104h */
155                 {1024, 768, 8},         /* 105h */
156                 {1280, 1024, 4},        /* 106h */
157                 {1280, 1024, 8}         /* 107h */
158         };
159         if(vbe_ver >= 0x0102) {
160                 mi->width = vbemi->xres;
161                 mi->height = vbemi->yres;
162                 mi->bpp = vbemi->bpp;
163         } else {
164                 if((mode & 0xff) > 7) {
165                         return -1;
166                 }
167                 mi->width = stdmode[mode & 0xff].width;
168                 mi->height = stdmode[mode & 0xff].height;
169                 mi->bpp = stdmode[mode & 0xff].bpp;
170         }
171         return 0;
172 }