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