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