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