]> 4ch.mooo.com Git - 16.git/blob - src/util/setres.c
design ww
[16.git] / src / util / setres.c
1 /*----------------------------------------------------------------------------\r
2 Sets text video modes\r
3 Chris Giese     <geezer@execpc.com>     http://my.execpc.com/~geezer/\r
4 This code is public domain (no copyright).\r
5 You can do whatever you want with it.\r
6 Release date: March 31, 2009\r
7 \r
8 Compile with Turbo C, Borland C for DOS, or 16-bit Watcom C. I used:\r
9         bcc -O2 -2 -Z -d -mt -f- -w -c setres.c\r
10         tlink /Lc:\bc\lib /x/t c0t.obj setres.obj,setres.com,,cs.lib\r
11 \r
12 On one of my systems, the following video modes are supported:\r
13   40x25[b ] 40x50[b ]  80x25[b ]  80x50[b ] 132x25[v ] 132x43[v ]\r
14   40x30[tb] 40x60[tb]  80x30[tb]  80x60[tb]  90x25[tb]  90x30[tb]\r
15   90x50[tb] 90x60[tb] 132x30[tv] 132x50[tv] 132x60[tv]\r
16 \r
17 [ b]=VGA BIOS (INT 10h AH=00h) modes    [tb]=tweaked VGA BIOS modes\r
18 [ v]=VBE BIOS (INT 10h AX=4F0xh) modes  [tv]=tweaked VBE BIOS modes\r
19 \r
20 The 'tweaked' modes start with a VGA or VBE BIOS mode, then write to the\r
21 CRTC registers to change the resolution. By default, this will happen only\r
22 if INT 10h AX=4F00h reports that the hardware is register-compatible with\r
23 VGA and INT 10h AX=4F01h reports that the mode is also register-compatible\r
24 with VGA. '-v' option overrides this -- use it at your own risk. Tweaking\r
25 does not (should not?) change the sync frequencies to unsupported values.\r
26 ----------------------------------------------------------------------------*/\r
27 #include <string.h> /* strcpy() */\r
28 #include <stdlib.h> /* realloc(), atoi() */\r
29 #include <stdio.h> /* printf(), putchar() */\r
30 #include <ctype.h> /* tolower() */\r
31 /* union REGS, struct SREGS, int86(), int86x(), FP_SEG(), FP_OFF(), */\r
32 #include <dos.h> /* pokeb(), poke(), inportb(), outportb() */\r
33 #if 0\r
34 #include <stdint.h>\r
35 #else\r
36 typedef unsigned char   uint8_t;\r
37 typedef unsigned short  uint16_t;\r
38 typedef unsigned long   uint32_t;\r
39 #endif\r
40 \r
41 #if defined(__TURBOC__)\r
42 #include <conio.h> /* clrscr() */\r
43 \r
44 #elif defined(__WATCOMC__)\r
45 #if defined(__386__)\r
46 #error 16-bit program -- compile with WCC.EXE\r
47 #endif\r
48 #define inportb(P)      inp(P)\r
49 #define outportb(P,V)   outp(P,V)\r
50 #define pokeb(S,O,V)    *(uint8_t  far *)MK_FP(S,O)=(V)\r
51 #define poke(S,O,V)     *(uint16_t far *)MK_FP(S,O)=(V)\r
52 #define peek(S,O)       *(uint16_t far *)MK_FP(S,O)\r
53 void clrscr(void)\r
54 {\r
55         union REGS regs;\r
56 \r
57         regs.h.ah = 0x02;\r
58         regs.h.bh = 0; /* page number */\r
59         regs.h.dh = 0; /* top-most row */\r
60         regs.h.dl = 0; /* left-most column */\r
61         int86(0x10, &regs, &regs);\r
62 }\r
63 \r
64 #else\r
65 #error Sorry, unsupported compiler\r
66 #endif\r
67 \r
68 /* besides the CRTC, VGA sequencer register #1 is also modified */\r
69 #define VGA_SEQ_INDEX           0x3C4\r
70 #define VGA_SEQ_DATA            0x3C5\r
71 /* emulation (color or mono) is read from this register --\r
72 it determines the CRTC I/O address (0x3B4 or 0x3D4) */\r
73 #define VGA_MISC_READ           0x3CC\r
74 #define VGA_CRTC_INDEX  (g_crtc_io + 0)\r
75 #define VGA_CRTC_DATA   (g_crtc_io + 1)\r
76 \r
77 /* this is like an X11 "modeline" */\r
78 typedef struct\r
79 {\r
80         unsigned disp, blank_start, sync_start, sync_end, blank_end, total;\r
81 } timing_t;\r
82 \r
83 /* for 30-line modes, use the 16-pixel-high font instead of 8-pixel */\r
84 static timing_t g_60_lines =\r
85 {\r
86 /*              blank   sync    sync    blank\r
87         disp    start   start   end     end     tot\r
88         ----    -----   -----   ----    -----   --- */\r
89         480,    488,    490,    493,    517,    525\r
90 };\r
91 \r
92 static timing_t g_90_cols =\r
93 {\r
94 /*              blank   sync    sync    blank\r
95         disp    start   start   end     end     tot\r
96         ----    -----   -----   ----    -----   --- */\r
97         90,     90,     95,     108,    98,     112\r
98 };\r
99 \r
100 typedef struct\r
101 {\r
102         unsigned char cols, rows;\r
103         unsigned mode_num;      /* VGA (<0x100) or VBE (>=0x100) mode number */\r
104         unsigned char set_font; /* set 8x8 font after mode-set or no? */\r
105         timing_t *horiz, *vert; /* CRTC timing 'tweaks' */\r
106 } mode_t;\r
107 \r
108 static mode_t *g_mode;\r
109 static unsigned g_crtc_io, g_num_modes;\r
110 /*****************************************************************************\r
111 *****************************************************************************/\r
112 static void add_mode(unsigned cols, unsigned rows, unsigned mode_num,\r
113                 unsigned set_font, timing_t *horiz, timing_t *vert)\r
114 {\r
115         mode_t *new_mode;\r
116 \r
117         new_mode = realloc(g_mode, (g_num_modes + 1) * sizeof(mode_t));\r
118         if(new_mode == NULL)\r
119         {\r
120                 printf("Error: out of memory\n");\r
121                 exit(2);\r
122         }\r
123         g_mode = new_mode;\r
124         new_mode = &g_mode[g_num_modes];\r
125         g_num_modes++;\r
126         new_mode->cols          = cols;\r
127         new_mode->rows          = rows;\r
128         new_mode->mode_num      = mode_num;\r
129         new_mode->set_font      = set_font;\r
130         new_mode->horiz         = horiz;\r
131         new_mode->vert          = vert;\r
132 }\r
133 /*****************************************************************************\r
134 *****************************************************************************/\r
135 static void dump_modes(void)\r
136 {\r
137         unsigned scn_wd, csr_x, i;\r
138         union REGS regs;\r
139 \r
140         scn_wd = peek(0x40, 0x4A);\r
141         printf("The following video modes are supported\n");\r
142         for(i = 0; i < g_num_modes; i++)\r
143         {\r
144 /* get cursor X position */\r
145                 regs.h.ah = 0x03;\r
146                 regs.h.bh = 0;\r
147                 int86(0x10, &regs, &regs);\r
148                 csr_x = regs.h.dl;\r
149 /* emit newline now if next listing will wrap */\r
150                 if(csr_x + 7 >= scn_wd)\r
151                         printf("\n");\r
152 /* resolution listing is 7 characters wide */\r
153                 printf("%4ux%-2u ", g_mode[i].cols, g_mode[i].rows);\r
154         }\r
155         printf("\n");\r
156 }\r
157 /*****************************************************************************\r
158 *****************************************************************************/\r
159 static mode_t *find_mode(unsigned cols, unsigned rows)\r
160 {\r
161         unsigned i;\r
162 \r
163         for(i = 0; i < g_num_modes; i++)\r
164         {\r
165                 if(g_mode[i].cols == cols && g_mode[i].rows == rows)\r
166                         return &g_mode[i];\r
167         }\r
168         return NULL;\r
169 }\r
170 /*****************************************************************************\r
171 *****************************************************************************/\r
172 static void set_horiz(timing_t *t)\r
173 {\r
174         unsigned i;\r
175 \r
176 /* remove write-protection from CRTC registers 0-5 (and 6-7) */\r
177         outportb(VGA_CRTC_INDEX, 17);\r
178         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x80);\r
179 /* set horizontal displayed */\r
180         outportb(VGA_CRTC_INDEX, 1);\r
181         outportb(VGA_CRTC_DATA, t->disp - 1);\r
182 /* set horizontal blanking start */\r
183         outportb(VGA_CRTC_INDEX, 2);\r
184         outportb(VGA_CRTC_DATA, t->blank_start);\r
185 /* set horizontal sync start */\r
186         outportb(VGA_CRTC_INDEX, 4);\r
187         outportb(VGA_CRTC_DATA, t->sync_start);\r
188 /* set horizontal sync end */\r
189         outportb(VGA_CRTC_INDEX, 5);\r
190         i = inportb(VGA_CRTC_DATA) & ~0x1F;\r
191         outportb(VGA_CRTC_DATA, (t->sync_end & 0x1F) | i);\r
192 /* set horizontal blanking end */\r
193         outportb(VGA_CRTC_INDEX, 3);\r
194         i = inportb(VGA_CRTC_DATA) & ~0x1F;\r
195         outportb(VGA_CRTC_DATA, (t->blank_end & 0x1F) | i);\r
196 /* set horizontal total */\r
197         outportb(VGA_CRTC_INDEX, 0);\r
198         outportb(VGA_CRTC_DATA, t->total - 5);\r
199 /* set "offset" (words per line) */\r
200         outportb(VGA_CRTC_INDEX, 19);\r
201         outportb(VGA_CRTC_DATA, t->disp / 2);\r
202 /* make characters 8 or 9 pixels wide */\r
203         outportb(VGA_SEQ_INDEX, 1);\r
204         i = inportb(VGA_SEQ_DATA) & ~0x01;\r
205         if(t->disp == 90)\r
206                 i |= 0x01;\r
207         outportb(VGA_SEQ_DATA, i);\r
208 }\r
209 /*****************************************************************************\r
210 *****************************************************************************/\r
211 static void set_vert(timing_t *t)\r
212 {\r
213         unsigned i, j;\r
214 \r
215 /* remove write-protection from CRTC registers 6-7 (and 0-5) */\r
216         outportb(VGA_CRTC_INDEX, 17);\r
217         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x80);\r
218 /* set vertical displayed */\r
219         i = t->disp - 1;\r
220         outportb(VGA_CRTC_INDEX, 18);\r
221         outportb(VGA_CRTC_DATA, i);\r
222         outportb(VGA_CRTC_INDEX, 7);\r
223         j = inportb(VGA_CRTC_DATA) & ~0x42;\r
224         if(i & 0x100)\r
225                 j |= 0x02;\r
226         if(i & 0x200)\r
227                 j |= 0x40;\r
228         outportb(VGA_CRTC_DATA, j);\r
229 /* set vertical blanking start */\r
230         i = t->blank_start;\r
231         outportb(VGA_CRTC_INDEX, 21);\r
232         outportb(VGA_CRTC_DATA, i);\r
233         outportb(VGA_CRTC_INDEX, 7);\r
234         j = inportb(VGA_CRTC_DATA) & ~0x08;\r
235         if(i & 0x100)\r
236                 j |= 0x08;\r
237         outportb(VGA_CRTC_DATA, j);\r
238 /* set vertical sync (retrace) start */\r
239         i = t->sync_start;\r
240         outportb(VGA_CRTC_INDEX, 16);\r
241         outportb(VGA_CRTC_DATA, i);\r
242         outportb(VGA_CRTC_INDEX, 7);\r
243         j = inportb(VGA_CRTC_DATA) & ~0x84;\r
244         if(i & 0x100)\r
245                 j |= 0x04;\r
246         if(i & 0x200)\r
247                 j |= 0x80;\r
248         outportb(VGA_CRTC_DATA, j);\r
249 /* set vertical sync (retrace) end */\r
250         outportb(VGA_CRTC_INDEX, 17);\r
251         i = inportb(VGA_CRTC_DATA) & ~0x0F;\r
252         outportb(VGA_CRTC_DATA, (t->sync_end & 0x0F) | i);\r
253 /* set vertical blanking end */\r
254         outportb(VGA_CRTC_INDEX, 22);\r
255 /*      i = inportb(VGA_CRTC_DATA) & ~0x7F;\r
256         outportb(VGA_CRTC_DATA, (t->blank_end & 0x7F) | i); */\r
257         outportb(VGA_CRTC_DATA, t->blank_end);\r
258 /* set vertical total */\r
259         i = t->total - 2;\r
260         outportb(VGA_CRTC_INDEX, 6);\r
261         outportb(VGA_CRTC_DATA, i);\r
262         outportb(VGA_CRTC_INDEX, 7);\r
263         j = inportb(VGA_CRTC_DATA) & ~0x21;\r
264         if(i & 0x100)\r
265                 j |= 0x01;\r
266         if(i & 0x200)\r
267                 j |= 0x20;\r
268         outportb(VGA_CRTC_DATA, j);\r
269 }\r
270 /*****************************************************************************\r
271 *****************************************************************************/\r
272 static void set_mode(mode_t *m)\r
273 {\r
274         union REGS regs;\r
275 \r
276 /* set (initial) mode; using either the VGA... */\r
277         if(m->mode_num < 0x100)\r
278         {\r
279                 regs.x.ax = m->mode_num;\r
280                 int86(0x10, &regs, &regs);\r
281         }\r
282 /* ...or VBE BIOS */\r
283         else\r
284         {\r
285                 regs.x.ax = 0x4F02;\r
286                 regs.x.bx = m->mode_num;\r
287                 int86(0x10, &regs, &regs);\r
288         }\r
289 /* set 8x8 font for 50- and 60-row VGA and tweaked modes */\r
290         if(m->set_font)\r
291         {\r
292                 regs.x.ax = 0x1112;\r
293                 regs.h.bl = 0;\r
294                 int86(0x10, &regs, &regs);\r
295         }\r
296         if(m->horiz || m->vert)\r
297         {\r
298 /* get CRTC address */\r
299                 if((inportb(VGA_MISC_READ) & 0x01) == 0)\r
300                         g_crtc_io = 0x3B4;      /* monochrome emulation */\r
301                 else\r
302                         g_crtc_io = 0x3D4;      /* color emulation */\r
303 /* tweak CRTC timing */\r
304                 if(m->horiz)\r
305                         set_horiz(m->horiz);\r
306                 if(m->vert)\r
307                         set_vert(m->vert);\r
308         }\r
309 /* let the BIOS know what we've done so text output works properly */\r
310         pokeb(0x40, 0x84, m->rows - 1);\r
311         poke(0x40, 0x4A, m->cols);\r
312 }\r
313 /*****************************************************************************\r
314 *****************************************************************************/\r
315 static void usage(void)\r
316 {\r
317         printf("Sets text video modes. Usage:\n"\r
318                 "\tSETRES [-vd] cols rows\t\t"  "-v skips VGA compatability test\n"\r
319                 "\t\t\t\t\t"                    "-d prints debug messages\n"\r
320                 "\tSETRES -l[vd]\t\t\t"         "lists available modes\n"\r
321                 "\tSETRES -a\t\t\t"             "displays author info\n");\r
322         exit(1);\r
323 }\r
324 /*****************************************************************************\r
325 *****************************************************************************/\r
326 int main(int arg_c, char *arg_v[])\r
327 {\r
328 /* structure used by INT 10h AX=4F00h */\r
329 #pragma pack(1)\r
330         static struct\r
331         {\r
332                 char sig[4];\r
333                 uint8_t ver_minor;\r
334                 uint8_t ver_major;\r
335                 char far *oem_name;\r
336                 uint32_t capabilities;   /* b1=1 for non-VGA board */\r
337                 uint16_t far *mode_list;\r
338                 char res0[494];         /* fields we don't care about */\r
339         } vbe_info;\r
340 /* structure used by INT 10h AX=4F01h */\r
341 #pragma pack(1)\r
342         static struct\r
343         {\r
344                 uint16_t mode_attrib;   /* b4=0 for text modes */\r
345                 char res0[16];          /* fields we don't care about */\r
346 /* OEM modes and VBE 1.2+ only: */\r
347                 uint16_t wd;\r
348                 uint16_t ht;\r
349                 uint8_t char_wd;\r
350                 uint8_t char_ht;\r
351                 char res1[232];         /* fields we don't care about */\r
352         } mode_info;\r
353 /* command-line options: */\r
354         char assume_vga, list_modes, info, debug;\r
355         unsigned i, num_count, wd, ht;\r
356         uint16_t far *mnp; /* Mode Number Pointer */\r
357         struct SREGS sregs;\r
358         union REGS regs;\r
359         mode_t *mode;\r
360         char *s;\r
361 \r
362 /* process command-line */\r
363         if(arg_c < 2)\r
364                 usage();\r
365         num_count = 0;\r
366         assume_vga = list_modes = info = debug = 0;\r
367         for(i = 1; i < arg_c; i++)\r
368         {\r
369 /* options */\r
370                 if(arg_v[i][0] == '-')\r
371                 {\r
372                         for(s = &arg_v[i][1]; *s != '\0'; s++)\r
373                         {\r
374                                 if(tolower(*s) == 'v')\r
375                                         assume_vga = 1;\r
376                                 else if(tolower(*s) == 'l')\r
377                                         list_modes = 1;\r
378                                 else if(tolower(*s) == 'a')\r
379                                         info = 1;\r
380                                 else if(tolower(*s) == 'd')\r
381                                         debug = 1;\r
382                                 else\r
383                                 {\r
384                                         printf("Error: invalid option '%c'\n",\r
385                                                 *s);\r
386                                         usage();\r
387                                 }\r
388                         }\r
389                 }\r
390 /* not an option, not a number */\r
391                 else if(atoi(arg_v[i]) == 0)\r
392                 {\r
393                         printf("Error: invalid parameter '%s'\n", arg_v[i]);\r
394                         usage();\r
395                 }\r
396 /* 1st number on command line = rows */\r
397                 else if(num_count == 0)\r
398                 {\r
399                         wd = atoi(arg_v[i]);\r
400                         num_count++;\r
401                 }\r
402 /* 2nd number on command line = cols */\r
403                 else if(num_count == 1)\r
404                 {\r
405                         ht = atoi(arg_v[i]);\r
406                         num_count++;\r
407                 }\r
408 /* too many numbers */\r
409                 else\r
410                 {\r
411                         printf("Error: invalid parameter '%s'\n", arg_v[i]);\r
412                         usage();\r
413                 }\r
414         }\r
415         if(info)\r
416         {\r
417                 printf( "Sets text video modes\n"\r
418                         "Chris Giese    <geezer@execpc.com>     http://my.execpc.com/~geezer/\n"\r
419                         "This code is public domain (no copyright).\n"\r
420                         "You can do whatever you want with it.\n"\r
421                         "Release date: March 31, 2009\n");\r
422                 return 1;\r
423         }\r
424 /* I assume these VGA text modes are supported on all systems: */\r
425         if(debug)\r
426                 printf("Adding VGA BIOS modes...\n");\r
427         add_mode(40, 25, 1, 0, NULL, NULL);\r
428         add_mode(40, 50, 1, 1, NULL, NULL);\r
429         add_mode(80, 25, 3, 0, NULL, NULL);\r
430         add_mode(80, 50, 3, 1, NULL, NULL);\r
431 /* check if VBE present */\r
432         if(debug)\r
433                 printf("VBE BIOS...");\r
434         strcpy(vbe_info.sig, "VBE2");\r
435         sregs.es = FP_SEG(&vbe_info);\r
436         regs.x.di = FP_OFF(&vbe_info);\r
437         regs.x.ax = 0x4F00;\r
438         int86x(0x10, &regs, &regs, &sregs);\r
439 /* (the indentation got a little ugly, so I'm going to use goto)\r
440 need VBE 1.2 or better */\r
441         if(regs.x.ax != 0x004F)\r
442         {\r
443                 if(debug)\r
444                         printf("not detected\n");\r
445                 goto NO_VBE;\r
446         }\r
447         if(debug)\r
448                 printf("version %u.%u; OEM name '%Fs'\n", vbe_info.ver_major,\r
449                         vbe_info.ver_minor,vbe_info.oem_name);\r
450         if(vbe_info.ver_major < 1 ||\r
451                 (vbe_info.ver_major == 1 && vbe_info.ver_minor < 2))\r
452         {\r
453                 if(debug)\r
454                         printf("Warning: VBE 1.2+ required\n");\r
455                 goto NO_VBE;\r
456         }\r
457 /* iterate over VBE modes */\r
458         if(debug)\r
459                 printf("Hex VBE mode numbers:\n");\r
460         for(mnp = vbe_info.mode_list; *mnp != 0xFFFF; mnp++)\r
461         {\r
462                 if(debug)\r
463                         printf("%4X ", *mnp);\r
464 /* get mode info */\r
465                 sregs.es = FP_SEG(&mode_info);\r
466                 regs.x.di = FP_OFF(&mode_info);\r
467                 regs.x.cx = *mnp;\r
468                 regs.x.ax = 0x4F01;\r
469                 int86x(0x10, &regs, &regs, &sregs);\r
470                 if(regs.x.ax != 0x004F)\r
471                         continue;\r
472 /* ignore all but text modes */\r
473                 if(mode_info.mode_attrib & 0x10)\r
474                         continue;\r
475 /* add VBE text mode to list */\r
476                 if(debug)\r
477                         printf("\nAdding VBE mode: %ux%u\n",\r
478                                 mode_info.wd, mode_info.ht);\r
479                 add_mode(mode_info.wd, mode_info.ht, *mnp, 0, NULL, NULL);\r
480         }\r
481         if(debug)\r
482         {\r
483                 if(assume_vga)\r
484                         printf("\n-v option; assuming hardware is VGA-compatible\n");\r
485                 else\r
486                 {\r
487                         printf("\nHardware is ");\r
488                         if(vbe_info.capabilities & 0x01)\r
489                                 printf("NOT ");\r
490                         printf("register-compatible with VGA\n");\r
491                 }\r
492         }\r
493 /* check if board is register-compatible with VGA\r
494 (unless overriden with '-v' option...) */\r
495         if(!assume_vga && (vbe_info.capabilities & 0x01))\r
496                 goto NO_VBE;\r
497 /* add 'tweaked' VGA modes to list */\r
498         if(debug)\r
499                 printf("Adding tweaked VGA modes...\n");\r
500         add_mode(40, 30, 1, 0, NULL,            &g_60_lines);\r
501         add_mode(40, 60, 1, 1, NULL,            &g_60_lines);\r
502         add_mode(80, 30, 3, 0, NULL,            &g_60_lines);\r
503         add_mode(80, 60, 3, 1, NULL,            &g_60_lines);\r
504         add_mode(90, 25, 3, 0, &g_90_cols,      NULL);\r
505         add_mode(90, 30, 3, 0, &g_90_cols,      &g_60_lines);\r
506         add_mode(90, 50, 3, 1, &g_90_cols,      NULL);\r
507         add_mode(90, 60, 3, 1, &g_90_cols,      &g_60_lines);\r
508 /* prepare to tweak VBE modes */\r
509         for(i = 0; i < g_num_modes; i++)\r
510         {\r
511                 static unsigned rows[] = { 25, 30, 50, 60 };\r
512 /**/\r
513                 unsigned j, set_font, tweak_vert;\r
514 \r
515 /* find VBE modes... */\r
516                 if(g_mode[i].mode_num < 0x100)\r
517                         continue;\r
518 /* ...with 25, 30, 50, or 60 rows */\r
519                 if(g_mode[i].rows != 25 && g_mode[i].rows != 30\r
520                         && g_mode[i].rows != 50 && g_mode[i].rows != 60)\r
521                                 continue;\r
522 /* check if this mode is register-compatible with VGA */\r
523                 if(!assume_vga)\r
524                 {\r
525                         sregs.es = FP_SEG(&mode_info);\r
526                         regs.x.di = FP_OFF(&mode_info);\r
527                         regs.x.cx = g_mode[i].mode_num;\r
528                         regs.x.ax = 0x4F01;\r
529                         int86x(0x10, &regs, &regs, &sregs);\r
530                         if(regs.x.ax != 0x004F)\r
531                                 continue;\r
532 /* xxx - b5 of mode_info.mode_attrib may be VBE 2.0+ only,\r
533 according to Ralf Brown's list */\r
534                         if(mode_info.mode_attrib & 0x20)\r
535                         {\r
536                                 if(debug)\r
537                                         printf("VBE mode 0x%X is NOT "\r
538                                                 "register-compatible with "\r
539                                                 "VGA; will not tweak\n",\r
540                                                 g_mode[i].mode_num);\r
541                                 continue;\r
542                         }\r
543                 }\r
544 /* now find mode with same number of columns\r
545 and complementary number of rows */\r
546                 for(j = 0; j < sizeof(rows) / sizeof(rows[0]); j++)\r
547                 {\r
548                         if(g_mode[i].rows == rows[j])\r
549                                 continue;\r
550 /* if the complementary mode does not already exist... */\r
551                         mode = find_mode(g_mode[i].cols, rows[j]);\r
552                         if(mode != NULL)\r
553                                 continue;\r
554 /* ...add it */\r
555                         set_font = (rows[j] >= 50);\r
556                         tweak_vert = (rows[j] == 30 || rows[j] == 60);\r
557                         if(debug)\r
558                                 printf("Adding tweaked VBE mode: %ux%u\n",\r
559                                         g_mode[i].cols, rows[j]);\r
560                         add_mode(g_mode[i].cols, rows[j],\r
561                                 g_mode[i].mode_num, set_font, NULL,\r
562                                 (tweak_vert ? &g_60_lines : NULL));\r
563                 }\r
564         }\r
565 NO_VBE:\r
566 /* just list the supported modes */\r
567         if(list_modes)\r
568         {\r
569                 dump_modes();\r
570                 return 0;\r
571         }\r
572 /* otherwise we need two numbers on the command-line\r
573 (the case of more than 2 numbers was handled above) */\r
574         if(num_count != 2)\r
575         {\r
576                 printf("Error: must specify cols and rows to set video mode\n");\r
577                 usage();\r
578         }\r
579 /* see if selected resolution supported */\r
580         mode = find_mode(wd, ht);\r
581         if(mode == NULL)\r
582         {\r
583                 printf("Error: mode %ux%u not supported\n", wd, ht);\r
584                 dump_modes();\r
585                 return 3;\r
586         }\r
587 /* SET MODE */\r
588         set_mode(mode);\r
589 #if 1\r
590 /* clear screen */\r
591         clrscr();\r
592 #else\r
593 /* DEBUG: display horizontal and vertical 'rulers' */\r
594 /*      textattr(0x17); doesn't work -- no blue background after clrscr() */\r
595         clrscr();\r
596         for(i = 1; i < 0xFF00; i += 2)\r
597                 pokeb(0xB800, i, 0x17);\r
598         for(i = 0; i < wd - 1; )\r
599         {\r
600                 if(i % 10 == 0)\r
601                 {\r
602                         printf("%03u", i);\r
603                         i += 3;\r
604                 }\r
605                 else\r
606                 {\r
607                         putchar(' ');\r
608                         i++;\r
609                 }\r
610         }\r
611         putchar('\n');\r
612         for(i = 1; i < ht - 4; i++)\r
613                 printf("%u\n", i);\r
614         printf("Current screen resolution is %ux%u\n", wd, ht);\r
615 #endif\r
616         return 0;\r
617 }\r