x68kConfig.c revision 9decb2cd
1/* $NetBSD: x68kConfig.c,v 1.8 2025/06/22 22:32:14 tsutsui Exp $ */
2/*-------------------------------------------------------------------------
3 * Copyright (c) 1996 Yasushi Yamasaki
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *-----------------------------------------------------------------------*/
26
27#include <stdarg.h>
28#include "x68k.h"
29#include "opaque.h"
30
31static PixmapFormatRec *x68kFormat = NULL;
32static PixmapFormatRec defaultFormat = {
33	1,
34	1,
35	BITMAP_SCANLINE_PAD
36};
37static X68kScreenRec x68kScreen[X68K_FB_TYPES];
38static X68kFbProcRec x68kFbProc[X68K_FB_TYPES];
39
40static int x68kKbdType = X68K_KB_STANDARD;
41
42/*-------------------------------------------------------------------------
43 * function "x68kGetScreenRec"
44 *
45 *  purpose:  get corresponding screen record
46 *  argument: (int)sindex       : screen index
47 *  returns:  (X68kScreenRec *) : X68k dependent screen record
48 *-----------------------------------------------------------------------*/
49X68kScreenRec *
50x68kGetScreenRec(int sindex)
51{
52    return &x68kScreen[sindex];
53}
54
55/*-------------------------------------------------------------------------
56 * function "x68kGetScreenRecByType"
57 *
58 *  purpose:  search screen record by type
59 *  argument: (int)type         : screen type
60 *  returns:  (X68kScreenRec *) : X68k dependent screen record
61 *-----------------------------------------------------------------------*/
62X68kScreenRec *
63x68kGetScreenRecByType(int type)
64{
65    int i;
66
67    for (i = 0; i < X68K_FB_TYPES; i++) {
68        if (x68kScreen[i].type == type)
69            return &x68kScreen[i];
70    }
71    return NULL;
72}
73
74/*-------------------------------------------------------------------------
75 * function "x68kGetFbProcRec"
76 *
77 *  purpose:  get corresponding frame buffer procedure record
78 *  argument: (int)sindex       : screen index
79 *  returns:  (X68kFbProcRec *) : frame buffer procedure record
80 *-----------------------------------------------------------------------*/
81X68kFbProcRec *
82x68kGetFbProcRec(int sindex)
83{
84    return &x68kFbProc[sindex];
85}
86
87/*-------------------------------------------------------------------------
88 * function "x68kRegisterPixmapFormats"
89 *
90 *  purpose:  register pixmap formats into ScreenInfo struct
91 *  argument: (ScreenInfo *)pScreenInfo
92 *  returns:  nothing
93 *-----------------------------------------------------------------------*/
94void
95x68kRegisterPixmapFormats(ScreenInfo *pScreenInfo)
96{
97    /* supports only one pixmap format for each screen type */
98    pScreenInfo->numPixmapFormats = 1;
99    pScreenInfo->formats[0] = defaultFormat;
100
101    if (x68kFormat)
102	pScreenInfo->formats[pScreenInfo->numPixmapFormats++] = *x68kFormat;
103}
104
105/*-------------------------------------------------------------------------
106 * function "x68kGetKbdType"
107 *
108 *  purpose:  get keyboard map type specified in the config file
109 *  argument: none
110 *  returns:  (int) : keyboard type
111 *-----------------------------------------------------------------------*/
112int
113x68kGetKbdType(void)
114{
115    return x68kKbdType;
116}
117
118/*-------------------------------------------------------------------------
119 * function "x68kConfig"
120 *
121 *  purpose:  process general configuration by reading "X68kConfig" file
122 *            <X11_LIBDIR> is the default location of this file
123 *  argument: nothing
124 *  returns:  the number of screens
125 *-----------------------------------------------------------------------*/
126const char *hostConfigFilename = "/etc/X68kConfig";
127const char *siteConfigFilename = X11_LIBDIR "/X68kConfig";
128const char *configFilename = NULL;
129static FILE *config;
130static char modeSet = FALSE;
131
132static int parseCommand(void);
133static void logConfig(void);
134
135int
136x68kConfig(void)
137{
138    MessageType filefrom = X_DEFAULT;
139
140    if (configFilename) {
141	config = fopen(configFilename, "r");
142	filefrom = X_CMDLINE;
143    } else {
144	configFilename = hostConfigFilename;
145	config = fopen(configFilename, "r");
146	if (config == NULL) {
147	    configFilename = siteConfigFilename;
148	    config = fopen(configFilename, "r");
149	}
150    }
151    if (config == NULL)
152	FatalError("Can't open X68kConfig file");
153
154    LogMessage(filefrom, "Using config file: \"%s\"\n", configFilename);
155
156    while (parseCommand())
157        ;
158    fclose(config);
159    if (!modeSet)
160        FatalError("No mode set.");
161    logConfig();
162    return 1;
163}
164
165
166/*-------------------------------------------------------------------------
167 *                       X68KConfig parsing part
168 *-----------------------------------------------------------------------*/
169static void parseError(int line, const char *str, ...);
170
171enum TokenType {
172    TOKEN_EOF,
173    TOKEN_SYMBOL,
174    TOKEN_LITERAL,
175    TOKEN_OPEN_PARENTHESIS,
176    TOKEN_CLOSE_PARENTHESIS
177};
178
179typedef struct {
180    enum TokenType type;
181    int line;
182    union {
183        char *symbol;
184        int literal;
185    } content;
186} Token;
187
188/*-------------------------------------------------------------------------
189 * function "getToken"
190 *
191 *  purpose:  cut out a token from configration file stream
192 *  argument: nothing
193 *  returns:  (Token *)  : cut token
194 *-----------------------------------------------------------------------*/
195static Token *
196getToken(void)
197{
198    int c;
199    static int line = 1;
200    Token *ret;
201
202    ret = malloc(sizeof(Token));
203    if (ret == NULL)
204        FatalError("Out of memory");
205    while (TRUE) {
206        /* slip white spaces */
207        do {
208            c = fgetc(config);
209            if (c == '\n')
210                line++;
211        } while (isspace(c));
212        if (c != ';')
213            break;
214        /* skip a comment */
215        do {
216            c = fgetc(config);
217        } while (c != '\n');
218        line++;
219    }
220    ret->line = line;
221    if (c == EOF) {
222        ret->type = TOKEN_EOF;
223        return ret;
224    }
225    /* is a symbol? */
226    if (isalpha(c)) {
227        int i = 0;
228        ret->content.symbol = malloc(32 * sizeof(char));
229        if (ret->content.symbol == NULL)
230            FatalError("Out of memory");
231        do {
232            if (i < 31)
233                ret->content.symbol[i++] = c;
234            c = fgetc(config);
235        } while (isalnum(c) || c == '_');
236        ungetc(c, config);
237        ret->content.symbol[i] = '\0';
238        ret->type = TOKEN_SYMBOL;
239        return ret;
240    }
241    /* is a literal number? */
242    if (isdigit(c)) {
243        char tmp[32];
244        int i = 0;
245        do {
246            if (i < 31)
247                tmp[i++] = c;
248            c = fgetc(config);
249        } while (isdigit(c));
250        ungetc(c, config);
251        tmp[i] = '\0';
252        if (sscanf(tmp, "%d", &ret->content.literal) != 1)
253            parseError(line, "illegal literal value");
254        ret->type = TOKEN_LITERAL;
255        return ret;
256    }
257    /* others */
258    switch(c) {
259        case '(':
260            ret->type = TOKEN_OPEN_PARENTHESIS;
261            break;
262        case ')':
263            ret->type = TOKEN_CLOSE_PARENTHESIS;
264            break;
265        default:
266            parseError(line, NULL);
267    }
268    return ret;
269}
270
271typedef struct {
272    const char *symbol;
273    void (*proc)(int argc, Token **argv);
274} Command;
275
276static void parseModeDef(int argc, Token **argv);
277static void parseMouse(int argc, Token **argv);
278static void parseKeyboard(int argc, Token **argv);
279static void parseMode(int argc, Token **argv);
280
281static const Command command[] = {
282    { "ModeDef", parseModeDef },
283    { "Mouse", parseMouse },
284    { "Keyboard", parseKeyboard },
285    { "Mode", parseMode },
286};
287#define NCOMMANDS (sizeof(command)/sizeof(command[0]))
288
289static const char *x68kTypeStr[] = {
290	[X68K_FB_NULL]    = NULL,
291	[X68K_FB_TEXT]    = "Text",
292	[X68K_FB_GRAPHIC] = "Graphic",
293};
294#define NTYPES (sizeof(x68kTypeStr) / sizeof(x68kTypeStr[0]))
295
296static const char *x68kClassStr[] = {
297	[StaticGray]  = "StaticGray",
298	[GrayScale]   = "GrayScale",
299	[StaticColor] = "StaticColor",
300	[PseudoColor] = "PseudoColor",
301	[TrueColor]   = "TrueColor",
302	[DirectColor] = "DirectColor",
303};
304#define NCLASSES (sizeof(x68kClassStr) / sizeof(x68kClassStr[0]))
305#define ClassInvalid	(-1)
306
307/*-------------------------------------------------------------------------
308 * function "parseCommand"
309 *
310 *  purpose:  parse generic command. every command parsing departs here.
311 *  argument: nothing
312 *  returns:  (int) : FALSE if there's no rest
313 *                    TRUE  otherwise
314 *-----------------------------------------------------------------------*/
315static int
316parseCommand(void)
317{
318    Token **argv = 0, *token;
319    int argc = 0;
320    int i;
321
322    token = getToken();
323    if (token->type == TOKEN_EOF)
324        return FALSE;
325    if (token->type != TOKEN_OPEN_PARENTHESIS)
326        parseError(token->line, "missing parenthesis");
327    free(token);
328
329    /* get command name and arguments */
330    while (TRUE) {
331        token = getToken();
332        if (token->type == TOKEN_EOF)
333            parseError(token->line, "reached EOF");
334        if (token->type == TOKEN_CLOSE_PARENTHESIS) {
335            free(token);
336            break;
337        }
338        argc++;
339        argv = realloc(argv, sizeof(Token *) * argc);
340        if (argv == NULL)
341            FatalError("Out of memory");
342        argv[argc-1] = token;
343    }
344    if (argc == 0)
345        return TRUE;
346
347    /* call corresponding command procedure */
348    if (argv[0]->type != TOKEN_SYMBOL)
349        parseError(argv[0]->line, "command name required");
350    for (i = 0; i < NCOMMANDS; i++) {
351        if (strcasecmp(command[i].symbol, argv[0]->content.symbol) == 0) {
352            /* parse command */
353            command[i].proc(argc, argv);
354            break;
355        }
356    }
357    if (i == NCOMMANDS)
358        parseError(argv[0]->line, "unknown command `%s'",
359                   argv[0]->content.symbol);
360
361    /* free arguments */
362    for (i = 0; i < argc; i++) {
363        if (argv[i]->type == TOKEN_SYMBOL)
364            free(argv[i]->content.symbol);
365        free(argv[i]);
366    }
367    free(argv);
368    return TRUE;
369}
370
371/*-------------------------------------------------------------------------
372 * function "checkArguments"
373 *
374 *  purpose:  examine the number of arguments and the type of each
375 *            argument.
376 *  argument: (int)n                 : correct number of arguments
377 *            (const enum TokenType *)type : table of types
378 *            (int)argc_m1           : actual number of arguments
379 *            (Token **)argv         : command and arguments
380 *  returns:  nothing
381 *-----------------------------------------------------------------------*/
382static void
383checkArguments(int n, const enum TokenType *type, int argc_m1, Token **argv)
384{
385    int i;
386
387    if (argc_m1 < n)
388        parseError(argv[0]->line, "too few arguments to command `%s'",
389                   argv[0]->content.symbol);
390    if (argc_m1 > n)
391        parseError(argv[0]->line, "too many arguments to command `%s'",
392                   argv[0]->content.symbol);
393    for (i = 0; i < n; i++) {
394        if (argv[i+1]->type != type[i])
395            parseError(argv[i+1]->line,
396                       "type mismatch. argument %d to command `%s'",
397                       i+1, argv[0]->content.symbol);
398    }
399}
400
401typedef struct _Mode {
402    struct _Mode *next;
403    const char *name;
404    int type;
405    int depth;
406    int class;
407    int width, height;
408    X68kFbReg reg;
409} Mode;
410
411static Mode *modeList = NULL;
412static Mode *modeChosen;
413
414/*-------------------------------------------------------------------------
415 * function "parseModeDef"
416 *
417 *  purpose:  define a mode
418 *  argument: (int)argc, (Token **)argv : command and arguments
419 *  returns:  nothing
420 *-----------------------------------------------------------------------*/
421static void
422parseModeDef(int argc, Token **argv)
423{
424    const enum TokenType argtype[] = {
425        /* name       type          depth          class      */
426        TOKEN_SYMBOL, TOKEN_SYMBOL, TOKEN_LITERAL, TOKEN_SYMBOL,
427        /* width       height       */
428        TOKEN_LITERAL, TOKEN_LITERAL,
429        /* register values */
430        TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL,
431        TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL,
432        TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL, TOKEN_LITERAL
433    };
434    Mode *mode;
435    char *symbol;
436    int type, class, width, height;
437
438    checkArguments(18, argtype, argc-1, argv);
439
440    mode = malloc(sizeof(Mode));
441    if (mode == NULL)
442        FatalError("Out of memory");
443    mode->name = strdup(argv[1]->content.symbol);
444
445    /* parse frame buffer type */
446    symbol = argv[2]->content.symbol;
447    mode->type = X68K_FB_NULL;
448    for (type = 1; type < NTYPES; type++) {
449        if (strcasecmp(x68kTypeStr[type], symbol) == 0) {
450            mode->type = type;
451            break;
452        }
453    }
454    if (mode->type == X68K_FB_NULL)
455        parseError(argv[2]->line, "unknown frame buffer type `%s'", symbol);
456
457    mode->depth = argv[3]->content.literal;
458
459    /* parse frame buffer class */
460    symbol = argv[4]->content.symbol;
461    mode->class = ClassInvalid;
462    for (class = 0; class < NCLASSES; class++) {
463	if (strcasecmp(x68kClassStr[class], symbol) == 0) {
464            mode->class = class;
465            break;
466	}
467    }
468    if (mode->class == ClassInvalid)
469        parseError(argv[4]->line, "unknown frame buffer class `%s'", symbol);
470
471    width = mode->width = argv[5]->content.literal;
472    height = mode->height = argv[6]->content.literal;
473
474    /* examine whether type, depth, class, width, and height are
475       a legal combination or not, and then set mode registers */
476    switch (type) {
477        case X68K_FB_TEXT:
478            if (mode->depth == 1 && class == StaticGray &&
479                width <= 1024 && height <= 1024) {
480                mode->reg.videoc.r1 = 0x21e4;
481                mode->reg.videoc.r2 = 0x0020;
482                goto legal;
483            }
484            break;
485        case X68K_FB_GRAPHIC:
486            switch (mode->depth) {
487                case 4:
488                    if ( (class == StaticGray || class == PseudoColor) &&
489                         width <= 1024 && height <= 1024 ) {
490                        mode->reg.videoc.r1 = 0x21e4;
491                        mode->reg.videoc.r2 = 0x0010;
492                        goto legal;
493                    }
494                    break;
495                case 8:
496                    if (class == PseudoColor &&
497                        width <= 512 && height <= 512) {
498                        mode->reg.videoc.r1 = 0x21e4;
499                        mode->reg.videoc.r2 = 0x0003;
500                        goto legal;
501                    }
502                    break;
503                case 15:
504                    if (class == TrueColor &&
505                        width <= 512 && height <= 512) {
506                        mode->reg.videoc.r1 = 0x21e4;
507                        mode->reg.videoc.r2 = 0x000f;
508                        goto legal;
509                    }
510                    break;
511            }
512            break;
513    }
514    parseError(argv[0]->line, "illegal combination of mode parameters");
515  legal:
516
517    /* store register values */
518    mode->reg.crtc.r00 = argv[7]->content.literal;
519    mode->reg.crtc.r01 = argv[8]->content.literal;
520    mode->reg.crtc.r02 = argv[9]->content.literal;
521    mode->reg.crtc.r03 = argv[10]->content.literal;
522    mode->reg.crtc.r04 = argv[11]->content.literal;
523    mode->reg.crtc.r05 = argv[12]->content.literal;
524    mode->reg.crtc.r06 = argv[13]->content.literal;
525    mode->reg.crtc.r07 = argv[14]->content.literal;
526    mode->reg.crtc.r08 = argv[15]->content.literal;
527    mode->reg.crtc.r20 = argv[16]->content.literal;
528    mode->reg.videoc.r0 = argv[17]->content.literal;
529    mode->reg.dotClock = argv[18]->content.literal;
530
531    /* set scroll registers to zero */
532    mode->reg.crtc.r12 = 0;    mode->reg.crtc.r13 = 0;
533    mode->reg.crtc.r14 = 0;    mode->reg.crtc.r15 = 0;
534    mode->reg.crtc.r16 = 0;    mode->reg.crtc.r17 = 0;
535    mode->reg.crtc.r18 = 0;    mode->reg.crtc.r19 = 0;
536
537    /* add new mode to linked mode list */
538    mode->next = modeList;
539    modeList = mode;
540}
541
542/*-------------------------------------------------------------------------
543 * function "parseMode"
544 *
545 *  purpose:  choose a mode from predefined modes
546 *  argument: (int)argc, (Token **)argv : command and arguments
547 *  returns:  nothing
548 *-----------------------------------------------------------------------*/
549static void
550parseMode(int argc, Token **argv)
551{
552    const enum TokenType argtype[]= { TOKEN_SYMBOL };
553    Mode *mode;
554
555    checkArguments(1, argtype, argc-1, argv);
556
557    /* search mode to set from mode list */
558    for (mode = modeList; mode != NULL; mode = mode->next) {
559        if (strcmp(mode->name, argv[1]->content.symbol) == 0)
560            break;
561    }
562    if (mode == NULL)
563        parseError(argv[1]->line, "undefined mode `%s'",
564                   argv[1]->content.symbol);
565
566    x68kScreen[0].type = mode->type;
567    x68kScreen[0].depth = mode->depth;
568    x68kScreen[0].class = mode->class;
569    x68kScreen[0].dpi = 75;
570    x68kScreen[0].x68kreg = mode->reg;
571    x68kScreen[0].scr_width = mode->width;
572    x68kScreen[0].scr_height = mode->height;
573
574    switch (mode->type) {
575        /* for TVRAM frame buffer */
576        case X68K_FB_TEXT:
577            x68kFbProc[0].open = x68kTextOpen;
578            x68kFbProc[0].init = x68kTextInit;
579            x68kFbProc[0].close = x68kTextClose;
580            x68kScreen[0].fb_width = 1024;
581            x68kScreen[0].fb_height = 1024;
582            break;
583        /* for GVRAM frame buffer */
584        case X68K_FB_GRAPHIC:
585            x68kFbProc[0].open = x68kGraphOpen;
586            x68kFbProc[0].init = x68kGraphInit;
587            x68kFbProc[0].close = x68kGraphClose;
588	    x68kFormat = malloc (sizeof(PixmapFormatRec));
589	    x68kFormat->scanlinePad = BITMAP_SCANLINE_PAD;
590            x68kFormat->bitsPerPixel = 16;
591            switch (mode->depth) {
592                case 4:
593                    x68kFormat->depth = 4;
594                    x68kScreen[0].fb_width = 1024;
595                    x68kScreen[0].fb_height = 1024;
596                    break;
597                case 8:
598                    x68kFormat->depth = 8;
599                    x68kScreen[0].fb_width = 512;
600                    x68kScreen[0].fb_height = 512;
601                    break;
602                case 15:
603                    x68kFormat->depth = 15;
604                    x68kScreen[0].fb_width = 512;
605                    x68kScreen[0].fb_height = 512;
606            }
607    }
608    modeSet = TRUE;
609    modeChosen = mode;
610}
611
612/*-------------------------------------------------------------------------
613 * function "parseMouse"
614 *
615 *  purpose:  set mouse attribute.
616 *  argument: (int)argc, (Token **)argv : command and arguments
617 *  returns:  nothing
618 *-----------------------------------------------------------------------*/
619static void
620parseMouse(int argc, Token **argv)
621{
622    const enum TokenType argtype[] = { TOKEN_SYMBOL };
623
624    checkArguments(1, argtype, argc-1, argv);
625    /* only `standard' mouse allowed */
626    if (strcasecmp("standard", argv[1]->content.symbol) != 0)
627        parseError(argv[1]->line, "unknown mouse type `%s'",
628                   argv[1]->content.symbol);
629}
630
631/*-------------------------------------------------------------------------
632 * function "parseKeyboard"
633 *
634 *  purpose:  select keyboard map
635 *  argument: (int)argc, (Token **)argv : command and arguments
636 *  returns:  nothing
637 *-----------------------------------------------------------------------*/
638static void
639parseKeyboard(int argc, Token **argv)
640{
641    const enum TokenType argtype[] = { TOKEN_SYMBOL };
642
643    checkArguments(1, argtype, argc-1, argv);
644    if (strcasecmp("standard", argv[1]->content.symbol) == 0) {
645        x68kKeySyms = &jisKeySyms;
646        x68kKbdType = X68K_KB_STANDARD;
647    } else if (strcasecmp("ascii", argv[1]->content.symbol) == 0) {
648        x68kKeySyms = &asciiKeySyms;
649        x68kKbdType = X68K_KB_ASCII;
650    } else
651        parseError(argv[1]->line, "unknown keyboard type `%s'",
652                   argv[1]->content.symbol);
653}
654
655/*-------------------------------------------------------------------------
656 * function "parseError"
657 *
658 *  purpose:  print error message to log and stderr and abort Xserver.
659 *  argument: (int)line         : the line in which some error was detected
660 *            (const char *)str : error message
661 *  returns:  nothing
662 *-----------------------------------------------------------------------*/
663static void
664parseError(int line, const char *str, ...)
665{
666    va_list arglist;
667
668    LogMessageVerb(X_ERROR, 0, "parse error in %s at line %d",
669        configFilename, line);
670    if (str != NULL) {
671        LogMessageVerb(X_NONE, 0, ":\n\t");
672	va_start(arglist, str);
673	LogVMessageVerb(X_NONE, 0, str, arglist);
674	va_end(arglist);
675    }
676    LogMessageVerb(X_NONE, 0, "\n");
677    FatalError("Error in X68k server config file. Exiting.\n");
678}
679
680/*-------------------------------------------------------------------------
681 * function "logConfig"
682 *
683 *  purpose:  print specified config settings to log.
684 *  argument: nothing
685 *  returns:  nothing
686 *-----------------------------------------------------------------------*/
687static void
688logConfig(void)
689{
690
691    LogMessage(X_CONFIG, "Using specified mode: \"%s\"\n", modeChosen->name);
692    LogMessage(X_CONFIG, "Type: %s, Class: %s, Size: %dx%d, Depth: %d\n",
693        x68kTypeStr[modeChosen->type], x68kClassStr[modeChosen->class],
694        modeChosen->width, modeChosen->height, modeChosen->depth);
695    LogMessage(X_CONFIG, "Keyboard: %s\n",
696        x68kKbdType == X68K_KB_ASCII ? "ascii" : "standard");
697    LogMessage(X_CONFIG, "Mouse: %s\n", "standard");
698}
699
700/* EOF x68kConfig.c */
701