setmode, crtc, list of standard modes
[dosdemo] / src / dos / vbe.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include <assert.h>
5 #include "vbe.h"
6 #include "cdpmi.h"
7
8
9 #define FIXPTR(ptr) \
10         do { \
11                 uint32_t paddr = (uint32_t)(ptr); \
12                 uint16_t pseg = paddr >> 16; \
13                 uint16_t poffs = paddr & 0xffff; \
14                 if(pseg == seg && poffs < 512) { \
15                         paddr = ((uint32_t)seg << 4) + poffs; \
16                 } else { \
17                         paddr = ((uint32_t)pseg << 4) + poffs; \
18                 } \
19                 (ptr) = (void*)paddr; \
20         } while(0)
21
22 /* hijack the "VESA" sig field, to pre-cache number of modes */
23 #define NMODES(inf) *(uint16_t*)((inf)->sig)
24 #define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2)
25
26 int vbe_info(struct vbe_info *info)
27 {
28         int i, num;
29         void *lowbuf;
30         uint16_t seg, sel;
31         uint16_t *modeptr;
32         struct dpmi_regs regs = {0};
33
34         assert(sizeof *info == 512);
35
36         if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) {
37                 return -1;
38         }
39         lowbuf = (void*)((uint32_t)seg << 4);
40
41         memcpy(lowbuf, "VBE2", 4);
42
43         regs.eax = 0x4f00;
44         regs.es = seg;
45         regs.edi = 0;
46         dpmi_int(0x10, &regs);
47
48         if((regs.eax & 0xffff) != 0x4f) {
49                 fprintf(stderr, "vbe_get_info (4f00) failed\n");
50                 dpmi_free(sel);
51                 return -1;
52         }
53
54         memcpy(info, lowbuf, sizeof *info);
55         dpmi_free(sel);
56
57         FIXPTR(info->oem_name);
58         FIXPTR(info->vendor);
59         FIXPTR(info->product);
60         FIXPTR(info->revstr);
61         FIXPTR(info->modes);
62         FIXPTR(info->accel_modes);
63
64         modeptr = info->modes;
65         while(*modeptr != 0xffff) {
66                 if(modeptr - info->modes >= 256) {
67                         modeptr = info->modes;
68                         break;
69                 }
70                 modeptr++;
71         }
72         NMODES(info) = modeptr - info->modes;
73
74         if(info->caps & VBE_ACCEL) {
75                 modeptr = info->accel_modes;
76                 while(*modeptr != 0xffff) {
77                         if(modeptr - info->accel_modes >= 256) {
78                                 modeptr = info->accel_modes;
79                                 break;
80                         }
81                         modeptr++;
82                 }
83                 NACCMODES(info) = modeptr - info->accel_modes;
84         }
85         return 0;
86 }
87
88 int vbe_num_modes(struct vbe_info *info)
89 {
90         return NMODES(info);
91 }
92
93 int vbe_mode_info(int mode, struct vbe_mode_info *minf)
94 {
95         int i, num;
96         void *lowbuf;
97         uint16_t seg, sel;
98         struct dpmi_regs regs = {0};
99
100         assert(sizeof *minf == 256);
101         assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e);
102
103         if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) {
104                 return -1;
105         }
106         lowbuf = (void*)((uint32_t)seg << 4);
107
108         regs.eax = 0x4f01;
109         regs.ecx = mode;
110         regs.es = seg;
111         dpmi_int(0x10, &regs);
112
113         if((regs.eax & 0xffff) != 0x4f) {
114                 fprintf(stderr, "vbe_mode_info (4f01) failed\n");
115                 dpmi_free(sel);
116                 return -1;
117         }
118
119         memcpy(minf, lowbuf, sizeof *minf);
120         dpmi_free(sel);
121         return 0;
122 }
123
124 void vbe_print_info(FILE *fp, struct vbe_info *vinf)
125 {
126         fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver));
127         if(VBE_VER_MAJOR(vinf->ver) >= 2) {
128                 fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr);
129                 if(vinf->caps & VBE_ACCEL) {
130                         fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver));
131                 }
132         } else {
133                 fprintf(fp, "oem: %s\n", vinf->oem_name);
134         }
135         fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64);
136
137         if(vinf->caps) {
138                 fprintf(fp, "caps:");
139                 if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8");
140                 if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga");
141                 if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank");
142                 if(vinf->caps & VBE_ACCEL) fprintf(fp, " af");
143                 if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock");
144                 if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs");
145                 if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip");
146                 if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt");
147                 fprintf(fp, "\n");
148         }
149
150         fprintf(fp, "%d video modes available\n", NMODES(vinf));
151         if(vinf->caps & VBE_ACCEL) {
152                 fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf));
153         }
154         fflush(fp);
155 }
156
157 void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf)
158 {
159         fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp);
160
161         switch(minf->mem_model) {
162         case VBE_TYPE_DIRECT:
163                 fprintf(fp, " (rgb");
164                 if(0) {
165         case VBE_TYPE_YUV:
166                         fprintf(fp, " (yuv");
167                 }
168                 fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize);
169                 break;
170         case VBE_TYPE_PLANAR:
171                 fprintf(fp, " (%d planes)", minf->num_planes);
172                 break;
173         case VBE_TYPE_PACKED:
174                 fprintf(fp, " (packed)");
175                 break;
176         case VBE_TYPE_TEXT:
177                 fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz);
178                 break;
179         case VBE_TYPE_CGA:
180                 fprintf(fp, " (CGA)");
181                 break;
182         case VBE_TYPE_UNCHAIN:
183                 fprintf(fp, " (unchained-%d)", minf->num_planes);
184                 break;
185         }
186         fprintf(fp, " %dpg", minf->num_img_pages);
187
188         if(minf->attr & VBE_ATTR_LFB) {
189                 fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr);
190         }
191
192         fprintf(fp, " [");
193         if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail");
194         if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt");
195         if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty");
196         if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color");
197         if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx");
198         if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga");
199         if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked");
200         if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb");
201         if(minf->attr & VBE_ATTR_DBLSCAN) fprintf(fp, " dblscan");
202         if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace");
203         if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf");
204         if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo");
205         if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual");
206         fprintf(fp, " ]\n");
207         fflush(fp);
208 }
209
210 int vbe_setmode(uint16_t mode)
211 {
212         struct dpmi_regs regs = {0};
213
214         regs.eax = 0x4f02;
215         regs.ebx = mode;
216         dpmi_int(0x10, &regs);
217
218         if((regs.eax & 0xffff) != 0x4f) {
219                 return -1;
220         }
221         return 0;
222 }
223
224 int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc)
225 {
226         void *lowbuf;
227         uint16_t seg, sel;
228         struct dpmi_regs regs = {0};
229
230         assert(sizeof *crtc == 59);
231
232         if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) {
233                 return -1;
234         }
235         lowbuf = (void*)((uint32_t)seg << 4);
236
237         memcpy(lowbuf, crtc, sizeof *crtc);
238
239         regs.eax = 0x4f02;
240         regs.ebx = mode;
241         regs.es = seg;
242         dpmi_int(0x10, &regs);
243
244         dpmi_free(sel);
245
246         if((regs.eax & 0xffff) != 0x4f) {
247                 return -1;
248         }
249         return 0;
250 }