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