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