f4ab00c556
git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/branches/UNSTABLE@1009 6ac86273-5f31-0410-b378-82cca8765d1b
710 lines
20 KiB
C
710 lines
20 KiB
C
/****************************************************************/
|
|
/* */
|
|
/* main.c */
|
|
/* DOS-C */
|
|
/* */
|
|
/* Main Kernel Functions */
|
|
/* */
|
|
/* Copyright (c) 1995, 1996 */
|
|
/* Pasquale J. Villani */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/* This file is part of DOS-C. */
|
|
/* */
|
|
/* DOS-C is free software; you can redistribute it and/or */
|
|
/* modify it under the terms of the GNU General Public License */
|
|
/* as published by the Free Software Foundation; either version */
|
|
/* 2, or (at your option) any later version. */
|
|
/* */
|
|
/* DOS-C is distributed in the hope that it will be useful, but */
|
|
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
|
|
/* the GNU General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU General Public */
|
|
/* License along with DOS-C; see the file COPYING. If not, */
|
|
/* write to the Free Software Foundation, Inc., */
|
|
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
|
|
/****************************************************************/
|
|
|
|
#include "portab.h"
|
|
#include "init-mod.h"
|
|
#include "dyndata.h"
|
|
|
|
#ifdef VERSION_STRINGS
|
|
static BYTE *mainRcsId =
|
|
"$Id$";
|
|
#endif
|
|
|
|
static char copyright[] =
|
|
"(C) Copyright 1995-2004 Pasquale J. Villani and The FreeDOS Project.\n"
|
|
"All Rights Reserved. This is free software and comes with ABSOLUTELY NO\n"
|
|
"WARRANTY; you can redistribute it and/or modify it under the terms of the\n"
|
|
"GNU General Public License as published by the Free Software Foundation;\n"
|
|
"either version 2, or (at your option) any later version.\n";
|
|
|
|
struct _KernelConfig InitKernelConfig BSS_INIT({0});
|
|
|
|
STATIC VOID init_internal_devices(void);
|
|
|
|
STATIC VOID update_dcb(struct dhdr FAR *);
|
|
STATIC VOID init_kernel(VOID);
|
|
STATIC VOID signon(VOID);
|
|
STATIC VOID init_shell(VOID);
|
|
STATIC VOID FsConfig(VOID);
|
|
STATIC VOID InitPrinters(VOID);
|
|
STATIC VOID InitSerialPorts(VOID);
|
|
STATIC void CheckContinueBootFromHarddisk(void);
|
|
STATIC void setup_int_vectors(void);
|
|
|
|
#ifdef _MSC_VER
|
|
BYTE _acrtused = 0;
|
|
|
|
__segment DosDataSeg = 0; /* serves for all references to the DOS DATA segment
|
|
necessary for MSC+our funny linking model
|
|
*/
|
|
__segment DosTextSeg = 0;
|
|
|
|
#endif
|
|
|
|
struct lol FAR *LoL = &DATASTART;
|
|
|
|
void ASMCFUNC FreeDOSmain(void)
|
|
{
|
|
#ifdef _MSC_VER
|
|
extern FAR prn_dev;
|
|
DosDataSeg = (__segment) & DATASTART;
|
|
DosTextSeg = (__segment) & prn_dev;
|
|
#endif
|
|
|
|
/* clear the Init BSS area (what normally the RTL does */
|
|
memset(_ib_start, 0, _ib_end - _ib_start);
|
|
|
|
/* if the kernel has been UPX'ed,
|
|
CONFIG info is stored at 50:e2 ..fc
|
|
and the bootdrive (passed from BIOS)
|
|
at 50:e0
|
|
*/
|
|
|
|
{
|
|
UBYTE drv;
|
|
UBYTE FAR *p = MK_PTR(UBYTE, 0, 0x5e2);
|
|
if (fmemcmp(p, "CONFIG", 6) == 0) /* UPXed */
|
|
drv = p[-2]; /* stored there by stub from exeflat.c */
|
|
|
|
/* !!! stub, added by exeflat.c for UPXed kernel, should store
|
|
boot drive# in the CONFIG-block, not outside (below) it. --avb */
|
|
|
|
else
|
|
{
|
|
drv = LoL->BootDrive;
|
|
|
|
/* !!! kernel.asm should store boot drive# from BL into
|
|
LowKernelConfig instead LoL->BootDrive. --avb */
|
|
|
|
p[-2] = drv; /* used in initdisk.c */
|
|
|
|
/* !!! initdisk.c:ReadAllPartitionTables() should get boot drive#
|
|
from InitKernelConfig, not at fixed address 0:5e0. --avb */
|
|
|
|
p = (UBYTE FAR*)&LowKernelConfig;
|
|
}
|
|
|
|
/* !!! boot drive# should be get from InitKernelConfig after
|
|
copying there FAR memory (from 0:5e0 or LowKernelConfig). --avb */
|
|
|
|
drv++; /* A:=1, B:=2 */
|
|
if (drv > 0x80)
|
|
drv = 3; /* C: */
|
|
LoL->BootDrive = drv;
|
|
|
|
fmemcpy(&InitKernelConfig, p, sizeof InitKernelConfig);
|
|
}
|
|
|
|
setup_int_vectors();
|
|
|
|
CheckContinueBootFromHarddisk();
|
|
|
|
signon();
|
|
init_kernel();
|
|
init_shell();
|
|
|
|
init_call_p_0(&Config); /* execute process 0 (the shell) */
|
|
}
|
|
|
|
/*
|
|
InitializeAllBPBs()
|
|
or MakeNortonDiskEditorHappy()
|
|
it has been determined, that FDOS's BPB tables are initialized,
|
|
only when used (like DIR H:).
|
|
at least one known utility (norton DE) seems to access them directly.
|
|
ok, so we access for all drives, that the stuff gets build
|
|
*/
|
|
void InitializeAllBPBs(VOID)
|
|
{
|
|
static char filename[] = "A:-@JUNK@-.TMP";
|
|
int drive, fileno;
|
|
for (drive = 'C'; drive < 'A' + LoL->nblkdev; drive++)
|
|
{
|
|
filename[0] = drive;
|
|
if ((fileno = open(filename, O_RDONLY)) >= 0)
|
|
close(fileno);
|
|
}
|
|
}
|
|
|
|
STATIC void PSPInit(void)
|
|
{
|
|
psp _seg *p = MK_SEG_PTR(psp, DOS_PSP);
|
|
|
|
fmemset(p, 0, sizeof(psp)); /* Clear out new psp first */
|
|
|
|
/* initialize all entries and exits */
|
|
p->ps_exit = 0x20cd; /* CP/M-like exit point: */
|
|
/* INT 20 opcode */
|
|
/* CP/M-like entry point: */
|
|
p->ps_farcall = 0x9a; /* FAR CALL opcode... */
|
|
p->ps_reentry = MK_FP(0, 0x30 * 4); /* ...entry address */
|
|
p->ps_unix[0] = 0xcd; /* unix style call: */
|
|
p->ps_unix[1] = 0x21; /* INT 21/RETF opcodes */
|
|
p->ps_unix[2] = 0xcb;
|
|
|
|
/* parent-child relationships */
|
|
/*p->ps_parent = 0;*/ /* parent psp segment */
|
|
p->ps_prevpsp = (VFP)-1l; /* previous psp address */
|
|
|
|
/* Environment and memory useage parameters */
|
|
/*p->ps_size = 0;*/ /* segment of memory beyond */
|
|
/* memory allocated to program */
|
|
/*p->ps_environ = 0;*/ /* environment paragraph */
|
|
|
|
/*p->ps_isv22 = NULL;*/ /* terminate handler */
|
|
/*p->ps_isv23 = NULL;*/ /* break handler */
|
|
/*p->ps_isv24 = NULL;*/ /* critical error handler */
|
|
|
|
/*p->ps_stack = NULL;*/ /* user stack pointer - int 21 */
|
|
|
|
/* File System parameters */
|
|
p->ps_maxfiles = sizeof p->ps_files; /* size of file table */
|
|
fmemset(p->ps_filetab = p->ps_files, 0xff, sizeof p->ps_files);
|
|
|
|
/*p->ps_fcb1.fcb_drive = 0;*/ /* 1st command line argument */
|
|
/*fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);*/
|
|
/*p->ps_fcb2.fcb_drive = 0;*/ /* 2nd command line argument */
|
|
/*fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);*/
|
|
|
|
/* this area reused for master environment */
|
|
/*p->ps_cmd.ctCount = 0;*/ /* local command line */
|
|
/*p->ps_cmd.ctBuffer[0] = '\r';*/ /* command tail */
|
|
|
|
/* !!! dirty hack: because bug in old FreeCOM, which wrongly
|
|
process empty environment in MS-DOS style, garbage empty
|
|
environment by dummy variable: --avb
|
|
*/
|
|
fmemcpy(&p->ps_cmd, "PATH=.", 6/*strlen("PATH=.")*/);
|
|
}
|
|
|
|
#ifndef __WATCOMC__
|
|
/* for WATCOMC we can use the ones in task.c */
|
|
intvec getvec(unsigned char intno)
|
|
{
|
|
intvec iv;
|
|
disable();
|
|
iv = *(intvec FAR *)MK_FP(0,4 * (intno));
|
|
enable();
|
|
return iv;
|
|
}
|
|
|
|
void setvec(unsigned char intno, intvec vector)
|
|
{
|
|
disable();
|
|
*(intvec FAR *)MK_FP(0,4 * intno) = vector;
|
|
enable();
|
|
}
|
|
#endif
|
|
|
|
STATIC void setup_int_vectors(void)
|
|
{
|
|
static struct vec
|
|
{
|
|
unsigned char intno;
|
|
size_t handleroff;
|
|
} vectors[] =
|
|
{
|
|
/* all of these are in the DOS DS */
|
|
{ 0x0, FP_OFF(int0_handler) }, /* zero divide */
|
|
{ 0x1, FP_OFF(empty_handler) }, /* single step */
|
|
{ 0x3, FP_OFF(empty_handler) }, /* debug breakpoint */
|
|
{ 0x6, FP_OFF(int6_handler) }, /* invalid opcode */
|
|
{ 0x20, FP_OFF(int20_handler) },
|
|
{ 0x21, FP_OFF(int21_handler) },
|
|
{ 0x22, FP_OFF(int22_handler) },
|
|
{ 0x24, FP_OFF(int24_handler) },
|
|
{ 0x25, FP_OFF(low_int25_handler) },
|
|
{ 0x26, FP_OFF(low_int26_handler) },
|
|
{ 0x27, FP_OFF(int27_handler) },
|
|
{ 0x28, FP_OFF(int28_handler) },
|
|
{ 0x2a, FP_OFF(int2a_handler) },
|
|
{ 0x2f, FP_OFF(int2f_handler) }
|
|
};
|
|
struct vec *pvec;
|
|
int i;
|
|
|
|
for (i = 0x23; i <= 0x3f; i++)
|
|
setvec(i, empty_handler);
|
|
for (pvec = vectors; pvec < ENDOF(vectors); pvec++)
|
|
setvec(pvec->intno, (intvec)MK_FP(FP_SEG(empty_handler), pvec->handleroff));
|
|
pokeb(0, 0x30 * 4, 0xea);
|
|
pokel(0, 0x30 * 4 + 1, (ULONG)cpm_entry);
|
|
|
|
/* these two are in the device driver area LOWTEXT (0x70) */
|
|
setvec(0x1b, got_cbreak);
|
|
setvec(0x29, int29_handler); /* required for printf! */
|
|
}
|
|
|
|
STATIC void init_kernel(void)
|
|
{
|
|
COUNT i;
|
|
|
|
LoL->os_setver_major = LoL->os_major = MAJOR_RELEASE;
|
|
LoL->os_setver_minor = LoL->os_minor = MINOR_RELEASE;
|
|
|
|
/* move kernel to high conventional RAM, just below the init code */
|
|
#ifdef __WATCOMC__
|
|
lpTop = MK_FP(_CS, 0);
|
|
#else
|
|
lpTop = MK_FP(_CS - (FP_OFF(_HMATextEnd) + 15) / 16, 0);
|
|
#endif
|
|
|
|
MoveKernel(FP_SEG(lpTop));
|
|
/* lpTop should be para-aligned */
|
|
lpTop = MK_FP(FP_SEG(lpTop) - 0xfff, 0xfff0);
|
|
|
|
/* Initialize IO subsystem */
|
|
init_internal_devices();
|
|
InitPrinters();
|
|
InitSerialPorts();
|
|
|
|
set_DTA(MK_FP(DOS_PSP, 0x80));
|
|
PSPInit();
|
|
init_PSPSet(DOS_PSP);
|
|
|
|
Init_clk_driver();
|
|
|
|
/* Do first initialization of system variable buffers so that */
|
|
/* we can read config.sys later. */
|
|
LoL->lastdrive = Config.cfgLastdrive;
|
|
|
|
blk_dev.dh_name[0] = dsk_init();
|
|
|
|
PreConfig();
|
|
|
|
/* Number of units */
|
|
if (blk_dev.dh_name[0] > 0)
|
|
update_dcb(&blk_dev);
|
|
|
|
/* Now config the temporary file system */
|
|
FsConfig();
|
|
|
|
/* Now process CONFIG.SYS */
|
|
DoConfig();
|
|
|
|
/* Close all (device) files */
|
|
for (i = 0; i < 20; i++)
|
|
close(i);
|
|
|
|
/* and do final buffer allocation. */
|
|
PostConfig();
|
|
|
|
/* Init the file system one more time */
|
|
FsConfig();
|
|
|
|
configDone();
|
|
|
|
InitializeAllBPBs();
|
|
|
|
DoInstall();
|
|
}
|
|
|
|
STATIC VOID FsConfig(VOID)
|
|
{
|
|
struct dpb FAR *dpb = LoL->DPBp;
|
|
int i;
|
|
|
|
/* Initialize the current directory structures */
|
|
for (i = 0; i < LoL->lastdrive; i++)
|
|
{
|
|
struct cds FAR *pcds_table = &LoL->CDSp[i];
|
|
pcds_table->cdsCurrentPath[0] = 'A' + i;
|
|
pcds_table->cdsCurrentPath[1] = ':';
|
|
pcds_table->cdsCurrentPath[2] = '\\';
|
|
pcds_table->cdsCurrentPath[3] = '\0';
|
|
pcds_table->cdsFlags = 0;
|
|
if (i < LoL->nblkdev && (LONG) dpb != -1l)
|
|
{
|
|
pcds_table->cdsDpb = dpb;
|
|
pcds_table->cdsFlags = CDSPHYSDRV;
|
|
dpb = dpb->dpb_next;
|
|
}
|
|
pcds_table->cdsStrtClst = 0xffff;
|
|
pcds_table->cdsParam = 0xffff;
|
|
pcds_table->cdsStoreUData = 0xffff;
|
|
pcds_table->cdsJoinOffset = 2;
|
|
}
|
|
|
|
/* Log-in the default drive. */
|
|
init_setdrive(LoL->BootDrive - 1);
|
|
|
|
/* The system file tables need special handling and are "hand */
|
|
/* built. Included is the stdin, stdout, stdaux and stdprn. */
|
|
/* a little bit of shuffling is necessary for compatibility */
|
|
|
|
/* sft_idx=0 is /dev/aux */
|
|
open("AUX", O_RDWR);
|
|
|
|
/* handle 1, sft_idx=1 is /dev/con (stdout) */
|
|
open("CON", O_RDWR);
|
|
|
|
/* 3 is /dev/aux */
|
|
dup2(STDIN, STDAUX);
|
|
|
|
/* 0 is /dev/con (stdin) */
|
|
dup2(STDOUT, STDIN);
|
|
|
|
/* 2 is /dev/con (stdin) */
|
|
dup2(STDOUT, STDERR);
|
|
|
|
/* 4 is /dev/prn */
|
|
open("PRN", O_WRONLY);
|
|
|
|
/* Initialize the disk buffer management functions */
|
|
/* init_call_init_buffers(); done from CONFIG.C */
|
|
}
|
|
|
|
STATIC VOID signon()
|
|
{
|
|
printf("\r%S"
|
|
"Kernel compatibility %d.%d - "
|
|
#if defined(__BORLANDC__)
|
|
"BORLANDC"
|
|
#elif defined(__TURBOC__)
|
|
"TURBOC"
|
|
#elif defined(_MSC_VER)
|
|
"MSC"
|
|
#elif defined(__WATCOMC__)
|
|
"WATCOMC"
|
|
#elif defined(__GNUC__)
|
|
"GNUC" /* this is hypothetical only */
|
|
#else
|
|
#error Unknown compiler
|
|
generate some bullshit error here, as the compiler should be known
|
|
#endif
|
|
#if defined (I386)
|
|
" - 80386 CPU required"
|
|
#elif defined (I186)
|
|
" - 80186 CPU required"
|
|
#endif
|
|
|
|
#ifdef WITHFAT32
|
|
" - FAT32 support"
|
|
#endif
|
|
"\n\n%s",
|
|
MK_FP(FP_SEG(LoL), FP_OFF(LoL->os_release)),
|
|
MAJOR_RELEASE, MINOR_RELEASE, copyright);
|
|
}
|
|
|
|
STATIC void init_shell()
|
|
{
|
|
/* if stepping CONFIG.SYS (F5/F8), tell COMMAND.COM about it */
|
|
/* (insert /D, /Y as first argument) */
|
|
if (askCommand & (ASK_TRACE | ASK_SKIPALL))
|
|
{
|
|
PStr p = Config.cfgShell - 1; /* find end of command name */
|
|
|
|
/* too long line -> truncate it to make space for "/Y \0" */
|
|
Config.cfgShell[sizeof Config.cfgShell - 4] = '\0';
|
|
|
|
do p++; while ((UBYTE)*p > ' ' && *p != '/');
|
|
|
|
if (*p == ' ' || *p == '\t')
|
|
p++; /* place option after space */
|
|
|
|
{
|
|
PStr q = p;
|
|
while (*q++); /* find end of command line */
|
|
/* shift tail to right by 3 to make room for option */
|
|
do
|
|
{
|
|
q--;
|
|
q[3] = q[0];
|
|
} while (q > p);
|
|
}
|
|
|
|
p[0] = '/', p[1] = 'Y', p[2] = ' '; /* single step AUTOEXEC */
|
|
if (askCommand & ASK_SKIPALL)
|
|
p[1] = 'D'; /* disable AUTOEXEC */
|
|
}
|
|
}
|
|
|
|
/* check for a block device and update device control block */
|
|
STATIC VOID update_dcb(struct dhdr FAR * dhp)
|
|
{
|
|
int nunits = dhp->dh_name[0];
|
|
struct dpb FAR *dpb = LoL->DPBp;
|
|
|
|
if (LoL->nblkdev)
|
|
{
|
|
while ((LONG) dpb->dpb_next != -1l)
|
|
dpb = dpb->dpb_next;
|
|
dpb = dpb->dpb_next =
|
|
KernelAlloc(nunits * sizeof(struct dpb), 'E', Config.cfgDosDataUmb);
|
|
}
|
|
|
|
{
|
|
int i = 0;
|
|
do
|
|
{
|
|
dpb->dpb_next = dpb + 1;
|
|
dpb->dpb_unit = LoL->nblkdev;
|
|
if (LoL->nblkdev < LoL->lastdrive && LoL->CDSp)
|
|
{
|
|
LoL->CDSp[LoL->nblkdev].cdsDpb = dpb;
|
|
LoL->CDSp[LoL->nblkdev].cdsFlags = CDSPHYSDRV;
|
|
}
|
|
LoL->nblkdev++;
|
|
dpb->dpb_subunit = i;
|
|
dpb->dpb_device = dhp;
|
|
dpb->dpb_flags = M_CHANGED;
|
|
dpb++;
|
|
i++;
|
|
} while (i < nunits);
|
|
}
|
|
(dpb - 1)->dpb_next = (VFP)-1l;
|
|
}
|
|
|
|
/* If r_top is NULL, this is an internal driver */
|
|
BOOL init_device(struct dhdr FAR * dhp, PCStr cmdLine, int mode, VFP *r_top)
|
|
{
|
|
request rq;
|
|
|
|
rq.r_unit = 0;
|
|
rq.r_status = 0;
|
|
rq.r_command = C_INIT;
|
|
rq.r_length = sizeof(request);
|
|
rq.r_endaddr = r_top ? *r_top : lpTop;
|
|
rq.r_bpbptr = (VFP)cmdLine;
|
|
rq.r_firstunit = LoL->nblkdev;
|
|
|
|
execrh(&rq, dhp);
|
|
|
|
/*
|
|
* Added needed Error handle
|
|
*/
|
|
if ((rq.r_status & (S_ERROR | S_DONE)) == S_ERROR)
|
|
return TRUE;
|
|
|
|
if (r_top)
|
|
{
|
|
/* Don't link in device drivers which do not take up memory */
|
|
if (rq.r_endaddr == (BYTE FAR *) dhp)
|
|
return TRUE;
|
|
|
|
/* Fix for multisegmented device drivers: */
|
|
/* If there are multiple device drivers in a single driver file, */
|
|
/* only the END ADDRESS returned by the last INIT call should be */
|
|
/* the used. It is recommended that all the device drivers in */
|
|
/* the file return the same address */
|
|
|
|
if (FP_OFF(dhp->dh_next) == 0xffff)
|
|
{
|
|
char name[8];
|
|
PCStr q;
|
|
{
|
|
UBYTE ch;
|
|
PCStr p = cmdLine;
|
|
q = p; /* position after path */
|
|
do /* find driver name after path */
|
|
{
|
|
ch = *p;
|
|
p++;
|
|
if (ch == ':' || ch == '\\' || ch == '/')
|
|
q = p;
|
|
} while (ch > ' ');
|
|
}
|
|
{
|
|
int i = 0;
|
|
do /* extract driver name */
|
|
{
|
|
UBYTE ch = *q;
|
|
if (ch <= ' ' || ch == '.')
|
|
ch = '\0'; /* copy name, without extension */
|
|
name[i] = ch;
|
|
if (ch == '\0')
|
|
break;
|
|
i++, q++;
|
|
} while (i < sizeof name);
|
|
}
|
|
KernelAllocPara(FP_SEG(alignNextPara(rq.r_endaddr)) - FP_SEG(dhp),
|
|
'D', name, mode);
|
|
}
|
|
|
|
/* Another fix for multisegmented device drivers: */
|
|
/* To help emulate the functionallity experienced with other DOS */
|
|
/* operating systems when calling multiple device drivers in a */
|
|
/* single driver file, save the end address returned from the */
|
|
/* last INIT call which will then be passed as the end address */
|
|
/* for the next INIT call. */
|
|
|
|
*r_top = rq.r_endaddr;
|
|
}
|
|
|
|
if (!(dhp->dh_attr & ATTR_CHAR) && (rq.r_nunits != 0))
|
|
{
|
|
dhp->dh_name[0] = rq.r_nunits;
|
|
update_dcb(dhp);
|
|
}
|
|
|
|
if (dhp->dh_attr & ATTR_CONIN)
|
|
LoL->syscon = dhp;
|
|
else if (dhp->dh_attr & ATTR_CLOCK)
|
|
LoL->clock = dhp;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC void init_internal_devices(void)
|
|
{
|
|
struct dhdr far *device = &LoL->nul_dev;
|
|
|
|
/* Initialize driver chain */
|
|
do {
|
|
/* ??? is cmdLine "\n" for internal devices required? --avb */
|
|
init_device(device, "\n", 0, NULL);
|
|
device = device->dh_next;
|
|
}
|
|
while (FP_OFF(device) != 0xffff);
|
|
}
|
|
|
|
/*
|
|
Initialize all printers
|
|
this should work. IMHO, this might also be done on first use
|
|
of printer, as I never liked the noise by a resetting printer, and
|
|
I usually much more often reset my system, then I print :-)
|
|
*/
|
|
|
|
STATIC VOID InitPrinters(VOID)
|
|
{
|
|
iregs r;
|
|
int num_printers, i;
|
|
|
|
init_call_intr(0x11, &r); /* get equipment list */
|
|
|
|
num_printers = (r.a.x >> 14) & 3; /* bits 15-14 */
|
|
|
|
for (i = 0; i < num_printers; i++)
|
|
{
|
|
r.a.x = 0x0100; /* initialize printer */
|
|
r.d.x = i;
|
|
init_call_intr(0x17, &r);
|
|
}
|
|
}
|
|
|
|
STATIC VOID InitSerialPorts(VOID)
|
|
{
|
|
iregs r;
|
|
int serial_ports, i;
|
|
|
|
init_call_intr(0x11, &r); /* get equipment list */
|
|
|
|
serial_ports = (r.a.x >> 9) & 7; /* bits 11-9 */
|
|
|
|
for (i = 0; i < serial_ports; i++)
|
|
{
|
|
r.a.x = 0xA3; /* initialize serial port to 2400,n,8,1 */
|
|
r.d.x = i;
|
|
init_call_intr(0x14, &r);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************
|
|
if kernel.config.BootHarddiskSeconds is set,
|
|
the default is to boot from harddisk, because
|
|
the user is assumed to just have forgotten to
|
|
remove the floppy/bootable CD from the drive.
|
|
|
|
user has some seconds to hit ANY key to continue
|
|
to boot from floppy/cd, else the system is
|
|
booted from HD
|
|
*/
|
|
|
|
static int EmulatedDriveStatus(int drive,char statusOnly)
|
|
{
|
|
iregs r;
|
|
char buffer[0x13];
|
|
buffer[0] = 0x13;
|
|
|
|
r.AH = 0x4b; /* bootable CDROM - get status */
|
|
r.AL = statusOnly;
|
|
r.DL = (char)drive;
|
|
r.SI = (int)buffer;
|
|
init_call_intr(0x13, &r);
|
|
return r.FLAGS & 1; /* carry flag */
|
|
}
|
|
|
|
STATIC void CheckContinueBootFromHarddisk(void)
|
|
{
|
|
char *bootedFrom = "Floppy/CD";
|
|
|
|
if (InitKernelConfig.BootHarddiskSeconds <= 0)
|
|
return;
|
|
|
|
if (LoL->BootDrive >= 3)
|
|
{
|
|
#if 0
|
|
if (EmulatedDriveStatus(0x80,1))
|
|
#endif
|
|
/* already booted from HD */
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
if (EmulatedDriveStatus(0x00,1))
|
|
#endif
|
|
bootedFrom = "Floppy";
|
|
}
|
|
|
|
printf("\n"
|
|
"\n"
|
|
"\n"
|
|
" Hit any key within %d seconds to continue booot from %s\n"
|
|
" Hit 'H' or wait %d seconds to boot from Harddisk\n",
|
|
InitKernelConfig.BootHarddiskSeconds,
|
|
bootedFrom,
|
|
InitKernelConfig.BootHarddiskSeconds);
|
|
|
|
if (GetBiosKey(InitKernelConfig.BootHarddiskSeconds))
|
|
{
|
|
unsigned key = GetBiosKey(-1); /* remove key from buffer */
|
|
if ((UBYTE)key != 'h' && (UBYTE)key != 'H')
|
|
/* user has hit a key, continue to boot from floppy/CD */
|
|
return;
|
|
}
|
|
|
|
/* reboot from harddisk */
|
|
EmulatedDriveStatus(0x00,0);
|
|
EmulatedDriveStatus(0x80,0);
|
|
|
|
{
|
|
iregs r;
|
|
r.AX = 0x0201;
|
|
r.CX = 0x0001;
|
|
r.DX = 0x0080;
|
|
r.BX = 0x7c00;
|
|
r.ES = 0;
|
|
init_call_intr(0x13, &r);
|
|
}
|
|
|
|
/* now jump and run */
|
|
((void (far*)(void)) MK_FP(0,0x7c00))(); /* jump to boot sector */
|
|
}
|