1 /* pro_init.c: reset and exit routines
2 
3    Copyright (c) 1997-2004, Tarik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 #ifdef PRO
23 #include "pdp11_defs.h"
24 #include <stdlib.h>
25 #include <unistd.h>
26 
27 #ifdef __hpux__
28 #define seteuid(euid) setresuid(-1,(euid),-1)
29 #endif
30 
31 extern t_stat ttclose (void); /* from scp_tty.c */
32 extern int PC; /* from pdp11_cpu */
33 
34 #ifdef IOTRACE
35 FILE	*iotfptr = NULL;
36 #endif
37 
38 struct	sercall	*pro_la50device;
39 struct	sercall	*pro_kb;
40 struct	sercall	*pro_ptr;
41 struct	sercall	*pro_com;
42 
43 int	pro_la50device_port;
44 int	pro_kb_port;
45 int	pro_ptr_port;
46 int	pro_com_port;
47 
48 
49 #ifdef TRACE
50 /* PC Trace */
51 
52 LOCAL FILE		*tfptr = NULL;
53 
trace()54 int trace ()
55 {
56         if (tfptr)
57 	{
58 	  fprintf(tfptr, "%o\n", PC);
59 	  fflush(tfptr);
60 	}
61 	return SCPE_OK;
62 }
63 
trace_reset()64 LOCAL int trace_reset ()
65 {
66         if (!tfptr)
67 	  tfptr = fopen("trace","w");
68         else
69           fflush(tfptr);
70 
71 	return SCPE_OK;
72 }
73 #endif
74 
75 #ifdef IOTRACE
76 /* I/O Access Trace */
77 
iotrace_reset()78 LOCAL int iotrace_reset ()
79 {
80         if (!iotfptr)
81 	  iotfptr = fopen("iotrace","w");
82 	else
83 	  fflush(iotfptr);
84 
85 	return SCPE_OK;
86 }
87 #endif
88 
89 
90 /* Text parameter comparison */
91 
92 /* max = -1 for no suffix
93           0..9 for suffix */
94 
95 /* returns -1 if no match
96             0 if a string without a suffix matches (i.e. "kb")
97             0..max if a string with a suffix matches (i.e. "rx2") */
98 
scmp(char * s1,char * s2,int max,int p1,int p2,int numpar)99 LOCAL int scmp(char *s1, char *s2, int max, int p1, int p2, int numpar)
100 {
101 int	i, s1len, s2len;
102 
103 
104 	s1len = strlen(s1);
105 	s2len = strlen(s2);
106 
107 	if ((strncmp(s1, s2, s2len) == 0)
108 	    && ((numpar == p1) || (numpar == p2)))
109 	{
110 	  if ((max == -1) && (s1len == s2len))
111 	    return 0;
112 	  else if  (s1len == (s2len+1))
113 	  {
114 	    i = (int)s1[s2len] - 48;
115 	    if ((i>=0) && (i<=max))
116 	      return i;
117 	  }
118 	}
119 	return -1;
120 }
121 
122 
123 /* Serial device assignments */
124 
125 /* returns 0 if successful, -1 if not */
126 
assign_serial(char * s1,struct sercall ** dev,int * port)127 LOCAL int assign_serial(char *s1, struct sercall **dev, int *port)
128 {
129 int	i, j;
130 
131 
132 	j = 0;
133 
134 	if ((i = scmp(s1, "serial\0", 3, 1, 1, 1)) > -1)
135 	{
136 	  *dev = &pro_serial;
137 	  *port = i;
138 	}
139 	else if ((i = scmp(s1, "la50\0", -1, 1, 1, 1)) > -1)
140 	{
141 	  *dev = &pro_la50;
142 	  *port = 0;
143 	}
144 	else if (scmp(s1, "lk201\0", -1, 1, 1, 1) > -1)
145 	{
146 	  *dev = &pro_lk201;
147 	  *port = 0;
148 	}
149 	else if (scmp(s1, "digipad\0", -1, 1, 1, 1) > -1)
150 	{
151 	  *dev = &pro_digipad;
152 	  *port = 0;
153 	}
154 	else if (scmp(s1, "null\0", -1, 1, 1, 1) > -1)
155 	{
156 	  *dev = &pro_null;
157 	  *port = 0;
158 	}
159 	else
160 	  j = -1;
161 
162 	return j;
163 }
164 
165 
166 /* Main PRO reset routine */
167 
pro_reset()168 void pro_reset ()
169 {
170 #define		MAXPAR	4	/* max # of parameters */
171 
172 FILE		*fptr;
173 char		*eofptr;
174 char		str1[1024], str2[1024];
175 char		filename[1024];
176 char		*stra, *strv[MAXPAR];
177 unsigned char	h, l;
178 int		i, j, k, len, linenum, numpar, error, file_found;
179 char		*strtmp;
180 
181 
182 	printf("\n");
183 	printf("XHOMER: Digital Pro/350 emulator (version %s)\n", PRO_VERSION);
184 	printf("(Press ctrl-F1, while the emulator window has focus, to access the control menu)\n");
185 	printf("\n");
186 
187 	seteuid(getuid());
188 
189 	pro_csr = PRO_CSR_INIT;
190 
191 	pro_led = 0;
192 
193 
194 #ifndef BUILTIN_ROMS
195 	/* Load boot/diagnostic ROM */
196 
197 	fptr = fopen("pro350.rom","r");
198 
199 	if (fptr == NULL)
200 	{
201 	  printf("Unable to open pro350.rom\n");
202 	  exit(0);
203 	}
204 
205 	for(i=0 ; i<8192; i++)
206 	{
207 	  l = getc(fptr);
208 	  h = getc(fptr);
209 	  ROM[i] = h*256+l;
210 	}
211 
212 	fclose(fptr);
213 
214 
215 	/* Load ID ROM */
216 
217 	fptr = fopen("id.rom","r");
218 
219 	if (fptr == NULL)
220 	{
221 	  printf("Unable to open id.rom\n");
222 	  exit(0);
223 	}
224 
225 	for(i=0 ; i<32; i++)
226 	{
227 	  l = getc(fptr);
228 	  h = getc(fptr);
229 	  IDROM[i] = h*256+l;
230 	}
231 
232 	fclose(fptr);
233 #endif
234 
235 
236 	/* Initialize battery-backed RAM */
237 
238 	fptr = fopen("bat.ram","r");
239 
240 	if (fptr == NULL)
241 	{
242 	  printf("Unable to open bat.ram - clearing battery-backed RAM\n");
243 	  memset(&BATRAM, 0, sizeof(BATRAM));
244 	}
245 	else
246 	{
247 	  for(i=0; i<50; i++)
248 	  {
249 	    l = getc(fptr);
250 	    h = getc(fptr);
251 	    BATRAM[i] = h*256+l;
252 	  }
253 
254 	  fclose(fptr);
255 	}
256 
257 
258 #if PRO_MEM_PRESENT
259 	/* Initialize memory expansion board ROM */
260 
261 	fptr = fopen("mem.rom","r");
262 
263 	if (fptr == NULL)
264 	{
265 	  printf("Unable to open mem.rom\n");
266 	  exit(0);
267 	}
268 
269 	for(i=0; i<1024; i++)
270 	{
271 	  l = getc(fptr);
272 	  MEMROM[i] = l;
273 	}
274 
275 	fclose(fptr);
276 #endif
277 
278 
279 	/* Make default serial port assignments */
280 
281 	pro_la50device = &pro_null;
282 	pro_la50device_port = 0;
283 
284 	pro_kb = &pro_lk201;
285 	pro_kb_port = 0;
286 
287 	pro_ptr = &pro_null;
288 	pro_ptr_port = 0;
289 
290 	pro_com = &pro_null;
291 	pro_com_port = 0;
292 
293 
294 	/* Make default rd assignments */
295 
296 	if (pro_rd_file != NULL)
297 	  free(pro_rd_file);
298 	pro_rd_file = strdup("pos32.rd");
299 
300 	pro_rd_heads = 0;
301 	pro_rd_cyls = 0;
302 	pro_rd_secs = 0;
303 
304 	/* Make default rx assignments */
305 
306 	for(k=0; k<4; k++)
307 	{
308 	  if (pro_rx_file[k] != NULL)
309 	    free(pro_rx_file[k]);
310 	  pro_rx_file[k] = strdup("");
311 	}
312 
313 	/* Make default disk image directory assignments */
314 
315 	for(k=0; k<4; k++)
316 	{
317 	  if (pro_rx_dir[k] != NULL)
318 	    free(pro_rx_dir[k]);
319 	  pro_rx_dir[k] = strdup("./");
320 	}
321 
322 	if (pro_rd_dir != NULL)
323 	  free(pro_rd_dir);
324 	pro_rd_dir = strdup("./");
325 
326 	/* Read configuration file */
327 
328 	file_found = 0;
329 
330 	/* First try home directory */
331 
332 	/* If $HOME is not defined, then look for /.xhomerrc */
333 
334 	sprintf(filename, "%.1000s/%s", getenv("HOME")?getenv("HOME"):"", ".xhomerrc");
335 	fptr = fopen(filename,"r");
336 
337 	if (fptr != NULL)
338 	  file_found = 1;
339 	else
340 	{
341 	  printf("%s not found\n", filename);
342 
343 	  /* Get current working directory.  If path exceeds ~1000 characters,
344 	     simply use "./" */
345 
346 	  if (getcwd(str1, 1000) == NULL)
347 	    sprintf(str1, ".");
348 
349 	  sprintf(filename, "%s/%s", str1, "xhomer.cfg");
350 	  fptr = fopen(filename,"r");
351 
352 	  if (fptr != NULL)
353 	    file_found = 1;
354 	  else
355 	    printf("%s not found\n", filename);
356 	}
357 
358 	if (!file_found)
359 	{
360 	  printf("Unable to open ~/.xhomerrc or xhomer.cfg - using built-in defaults\n");
361 	}
362 	else
363 	{
364 	  printf("Using %s\n", filename);
365 
366 	  linenum = 0;
367 	  do
368 	  {
369 	    linenum++;
370 	    eofptr = fgets(str1, 1024, fptr);
371 	    if (eofptr != 0)
372 	    {
373 	      /* Remove control characters, spaces and comments */
374 
375 	      j = 0;
376 
377 	      for(i=0; i<=strlen(str1); i++)
378 	        if (str1[i] == '#')
379 	        {
380 	          str2[j++] = 0;
381 	          break;
382 	        }
383 	        else if ((str1[i] > 32) || (str1[i] == 0))
384 	          str2[j++] = str1[i];
385 
386 	      /* Filter blank lines */
387 
388 	      if (strlen(str2) != 0)
389 	      {
390 	        /* Extract argument */
391 
392 	        /* XXX should these be freed? */
393 
394 	        stra = strtok(str2, "=");
395 
396 	        /* Extract up to four parameters */
397 
398 	        numpar = 0; /* # of parameters found */
399 
400 	        do
401 	        {
402 	          strv[numpar] = strtok(NULL, ",");
403 	          if (strv[numpar] == NULL)
404 	            break;
405 	          numpar++;
406 	        }
407 	        while (numpar < MAXPAR);
408 
409 	        /* Make assignments */
410 
411 	        error = 0;
412 
413 	        /* RD hard drive */
414 
415 	        if ((i = scmp(stra, "rd", 0, 1, 4, numpar)) > -1)
416 	        {
417 	          if (pro_rd_file != NULL)
418 	            free(pro_rd_file);
419 	          pro_rd_file = strdup(strv[0]);
420 
421 	          /* Check if geometry is defined */
422 
423 	          if (numpar == 4)
424 	          {
425 	            pro_rd_heads = atoi(strv[1]);
426 	            pro_rd_cyls = atoi(strv[2]);
427 	            pro_rd_secs = atoi(strv[3]);
428 	          }
429 	        }
430 
431 	        /* RX floppy */
432 
433 	        else if ((i = scmp(stra, "rx", 3, 1, 1, numpar)) > -1)
434 	        {
435 	          if (pro_rx_file[i] != NULL)
436 	            free(pro_rx_file[i]);
437 	          pro_rx_file[i] = strdup(strv[0]);
438 
439 	          /* Close drive */
440 
441 	          pro_rx_closed[i] = 1;
442 	        }
443 
444 	        /* RD image directory */
445 
446 	        else if (scmp(stra, "rd_dir", -1, 1, 1, numpar) > -1)
447 	        {
448 	          if (pro_rd_dir != NULL)
449 	            free(pro_rd_dir);
450 	          pro_rd_dir = strdup(strv[0]);
451 
452 	          len = strlen(pro_rd_dir);
453 
454 	          if (pro_rd_dir[len-1] != '/')
455 	          {
456 	            strtmp = strdup(pro_rd_dir);
457 	            free(pro_rd_dir);
458 	            pro_rd_dir = malloc(len+2);
459 	            strcpy(pro_rd_dir, strtmp);
460 	            strcat(pro_rd_dir, "/");
461 	            free(strtmp);
462 	          }
463 	        }
464 
465 	        /* RX image directory */
466 
467 	        else if (scmp(stra, "rx_dir", -1, 1, 1, numpar) > -1)
468 	        {
469 	          for(k=0; k<4; k++)
470 	          {
471 	            if (pro_rx_dir[k] != NULL)
472 	              free(pro_rx_dir[k]);
473 	            pro_rx_dir[k] = strdup(strv[0]);
474 
475 	            len = strlen(pro_rx_dir[k]);
476 
477 	            if (pro_rx_dir[k][len-1] != '/')
478 	            {
479 	              strtmp = strdup(pro_rx_dir[k]);
480 	              free(pro_rx_dir[k]);
481 	              pro_rx_dir[k] = malloc(len+2);
482 	              strcpy(pro_rx_dir[k], strtmp);
483 	              strcat(pro_rx_dir[k], "/");
484 	              free(strtmp);
485 	            }
486 	          }
487 	        }
488 
489 	        /* Serial device names */
490 
491 	        else if ((i = scmp(stra, "serial", 3, 1, 1, numpar)) > -1)
492 	        {
493 	          if (pro_serial_devname[i] != NULL)
494 	            free(pro_serial_devname[i]);
495 	          pro_serial_devname[i] = strdup(strv[0]);
496 	        }
497 
498 	        /* LA50 device */
499 
500 	        else if (scmp(stra, "la50", -1, 1, 1, numpar) > -1)
501 	        {
502 	          if (assign_serial(strv[0], &pro_la50device, &pro_la50device_port) == -1)
503 	            error = 1;
504 	        }
505 
506 	        /* Keyboard port */
507 
508 	        else if (scmp(stra, "kb", -1, 1, 1, numpar) > -1)
509 	        {
510 	          if (assign_serial(strv[0], &pro_kb, &pro_kb_port) == -1)
511 	            error = 1;
512 	        }
513 
514 	        /* Printer port */
515 
516 	        else if (scmp(stra, "ptr", -1, 1, 1, numpar) > -1)
517 	        {
518 	          if (assign_serial(strv[0], &pro_ptr, &pro_ptr_port) == -1)
519 	            error = 1;
520 	        }
521 
522 	        /* Communications port */
523 
524 	        else if (scmp(stra, "com", -1, 1, 1, numpar) > -1)
525 	        {
526 	          if (assign_serial(strv[0], &pro_com, &pro_com_port) == -1)
527 	            error = 1;
528 	        }
529 
530 	        /* Number of DGA framebuffers */
531 
532 	        else if (scmp(stra, "framebuffers", -1, 1, 1, numpar) > -1)
533 	        {
534 	          i = atoi(strv[0]);
535 	          if ((i < 0) || (i > 3))
536 	            error = 1;
537 	          else
538 	            pro_screen_framebuffers = i;
539 	        }
540 
541 	        /* Screen mode */
542 
543 	        else if (scmp(stra, "screen", -1, 1, 1, numpar) > -1)
544 	        {
545 	          if (scmp(strv[0], "window", -1, 1, 1, 1) > -1)
546 	            pro_screen_full = 0;
547 	          else if (scmp(strv[0], "full", -1, 1, 1, 1) > -1)
548 	            pro_screen_full = 1;
549 	          else
550 	            error = 1;
551 	        }
552 
553 	        /* Screen scale factors */
554 
555 	        else if (scmp(stra, "window_scale", -1, 1, 1, numpar) > -1)
556 	        {
557 	          i = atoi(strv[0]);
558 	          if (i < 1)
559 	            error = 1;
560 	          else
561 	            pro_screen_window_scale = i;
562 	        }
563 
564 	        else if (scmp(stra, "full_scale", -1, 1, 1, numpar) > -1)
565 	        {
566 	          i = atoi(strv[0]);
567 	          if (i < 1)
568 	            error = 1;
569 	          else
570 	            pro_screen_full_scale = i;
571 	        }
572 
573 	        /* Window position */
574 
575 	        else if (scmp(stra, "window_position", -1, 2, 2, numpar) > -1)
576 	        {
577 	          pro_window_x = atoi(strv[0]);
578 	          pro_window_y = atoi(strv[1]);
579 	        }
580 
581 	        /* Screen gamma */
582 
583 	        else if (scmp(stra, "screen_gamma", -1, 1, 1, numpar) > -1)
584 	        {
585 	          pro_screen_gamma = atoi(strv[0]);
586 	        }
587 
588 	        /* la50 DPI */
589 
590 	        else if (scmp(stra, "la50_dpi", -1, 1, 1, numpar) > -1)
591 	        {
592 	          i = atoi(strv[0]);
593 
594 	          if ((i != 300) && (i != 600))
595 	            error = 1;
596 	          else
597 	            pro_la50_dpi = i;
598 	        }
599 
600 	        /* Force year */
601 
602 	        else if (scmp(stra, "force_year", -1, 1, 1, numpar) > -1)
603 	        {
604 	          i = atoi(strv[0]);
605 
606 	          if ((i < -1) || (i > 99))
607 	            error = 1;
608 	          else
609 	            pro_force_year = i;
610 	        }
611 
612 		/* Printer port maintenance mode */
613 
614 		else if (scmp(stra, "maint_mode", -1, 1, 1, numpar) > -1)
615 		{
616 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
617 	            pro_maint_mode = 0;
618 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
619 	            pro_maint_mode = 1;
620 	          else
621 	            error = 1;
622 		}
623 
624 		/* Periodic interrupt throttle mode */
625 
626 		else if (scmp(stra, "int_throttle", -1, 1, 1, numpar) > -1)
627 		{
628 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
629 	            pro_int_throttle = 0;
630 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
631 	            pro_int_throttle = 1;
632 	          else
633 	            error = 1;
634 		}
635 
636 		else if (scmp(stra, "nine_workaround", -1, 1, 1, numpar) > -1)
637 		{
638 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
639 	            pro_nine_workaround = 0;
640 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
641 	            pro_nine_workaround = 1;
642 	          else
643 	            error = 1;
644 		}
645 
646 		else if (scmp(stra, "libc_workaround", -1, 1, 1, numpar) > -1)
647 		{
648 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
649 	            pro_libc_workaround = 0;
650 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
651 	            pro_libc_workaround = 1;
652 	          else
653 	            error = 1;
654 		}
655 
656 		else if (scmp(stra, "lp_workaround", -1, 1, 1, numpar) > -1)
657 		{
658 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
659 	            pro_lp_workaround = 0;
660 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
661 	            pro_lp_workaround = 1;
662 	          else
663 	            error = 1;
664 		}
665 
666 		else if (scmp(stra, "pcm", -1, 1, 1, numpar) > -1)
667 		{
668 	          if (scmp(strv[0], "off", -1, 1, 1, 1) > -1)
669 	            pro_screen_pcm = 0;
670 	          else if (scmp(strv[0], "on", -1, 1, 1, 1) > -1)
671 	            pro_screen_pcm = 1;
672 	          else
673 	            error = 1;
674 		}
675 
676 	        else
677 	          error = 1;
678 
679 	        if (error == 1)
680 	          printf("Config file error line %d: %s", linenum, str1);
681 	      }
682 	    }
683 	  }
684 	  while (eofptr != 0);
685 	  fclose(fptr);
686 	}
687 
688 
689 	pro_eq_reset();
690 
691 	pro_int_reset();
692 
693 	pro_clk_reset();
694 
695 	pro_mem_reset();
696 
697 	pro_kb_reset();
698 
699 	pro_ptr_reset();
700 
701 	pro_com_reset();
702 
703 	pro_rx_reset();
704 
705 	pro_rd_reset();
706 
707 	pro_menu_reset();
708 
709 	pro_vid_reset();
710 
711 #ifdef TRACE
712 	trace_reset();
713 #endif
714 
715 #ifdef IOTRACE
716 	iotrace_reset();
717 #endif
718 }
719 
720 
721 /* Exit routine */
722 
pro_exit()723 void pro_exit ()
724 {
725 FILE		*fptr;
726 unsigned char	h, l;
727 int		i;
728 
729 
730 	/* Write battery-backed RAM data back to file */
731 
732 	fptr = fopen("bat.ram","w");
733 
734 	if (fptr == NULL)
735 	{
736 	  printf("Unable to write to bat.ram\n");
737 	}
738 	else
739 	{
740 	  for(i=0; i<50; i++)
741 	  {
742 	    l = BATRAM[i] & 0xff;
743 	    h = (BATRAM[i] >> 8) & 0xff;
744 	    putc(l, fptr);
745 	    putc(h, fptr);
746 	  }
747 
748 	  fclose(fptr);
749 	}
750 
751 	pro_mem_exit();
752 
753 	pro_rx_exit();
754 
755 	pro_rd_exit();
756 
757 	pro_kb_exit();
758 
759 	pro_ptr_exit();
760 
761 	pro_com_exit();
762 
763 	pro_vid_exit();
764 
765 	/* Call scp_tty to restore terminal settings */
766 
767 	ttclose();
768 
769 	exit(0);
770 }
771 #endif
772