executor/src/device.c

417 lines
11 KiB
C

/* Copyright 1989 - 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
/* Forward declarations in DeviceMgr.h (DO NOT DELETE THIS LINE) */
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_device[] =
"$Id: device.c 63 2004-12-24 18:19:43Z ctm $";
#endif
#include "rsys/common.h"
#include "DeviceMgr.h"
#include "FileMgr.h"
#include "MemoryMgr.h"
#include "OSUtil.h"
#include "ResourceMgr.h"
#include "MenuMgr.h"
#include "ToolboxEvent.h"
#include "rsys/glue.h"
#include "rsys/mman.h"
#include "rsys/device.h"
#include "rsys/file.h"
#include "rsys/serial.h"
/*
* NOTE: The device manager now executes "native code" and code read
* in from resources. The latter is "RAM" based, the former is
* our version of "ROM" based. We use the same bit that the Mac
* uses to distinguish between the two, but our implementation of
* ROM based is incompatible with theirs. NOTE: even in our
* incompatible ROM based routines, we still byte swap the pointers
* that get us to the routines.
*/
A4(PUBLIC, OSErr, ROMlib_dispatch, ParmBlkPtr, p, /* INTERNAL */
BOOLEAN, async, DriverRoutineType, routine, INTEGER, trapn)
{
int devicen;
ramdriverhand ramdh;
DCtlHandle h;
OSErr retval;
typedef OSErr (*devfp_t)(ParmBlkPtr, DCtlPtr);
devfp_t procp;
devicen = -CW(p->cntrlParam.ioCRefNum) - 1;
if (devicen < 0 || devicen >= NDEVICES)
retval = badUnitErr;
else if (UTableBase == (DCtlHandlePtr) (long) CLC(0xFFFFFFFF) ||
(h = MR(MR(UTableBase)[devicen].p)) == 0 || (*h).p == 0)
retval = unitEmptyErr;
else {
HLock((Handle) h);
p->ioParam.ioTrap = CW(trapn);
if (async)
p->ioParam.ioTrap |= CWC(asyncTrpBit);
else
p->ioParam.ioTrap |= CWC(noQueueBit);
if (!(HxX(h, dCtlFlags) & CWC(RAMBASEDBIT))) {
switch (routine) {
case Open:
retval = (* (devfp_t) MR(HxP(h, dCtlDriver)->udrvrOpen))
(p, STARH(h));
break;
case Prime:
retval = (* (devfp_t) MR(HxP(h, dCtlDriver)->udrvrPrime))
(p, STARH(h));
break;
case Ctl:
retval = (* (devfp_t) MR(HxP(h, dCtlDriver)->udrvrCtl))
(p, STARH(h));
break;
case Stat:
retval = (* (devfp_t) MR(HxP(h, dCtlDriver)->udrvrStatus))
(p, STARH(h));
break;
case Close:
retval = (* (devfp_t) MR(HxP(h, dCtlDriver)->udrvrClose))
(p, STARH(h));
break;
default:
retval = fsDSIntErr;
break;
}
} else {
ramdh = (ramdriverhand) HxP(h, dCtlDriver);
LoadResource((Handle) ramdh);
HLock((Handle) ramdh);
switch (routine) {
case Open:
procp = (devfp_t) STARH(ramdh) + Hx(ramdh, drvrOpen);
break;
case Prime:
procp = (devfp_t) STARH(ramdh) + Hx(ramdh, drvrPrime);
break;
case Ctl:
procp = (devfp_t) STARH(ramdh) + Hx(ramdh, drvrCtl);
break;
case Stat:
procp = (devfp_t) STARH(ramdh) + Hx(ramdh, drvrStatus);
break;
case Close:
procp = (devfp_t) STARH(ramdh) + Hx(ramdh, drvrClose);
break;
default:
procp = 0;
break;
}
if (procp) {
LONGINT saved1, saved2, saved3, saved4, saved5, saved6, saved7,
savea2, savea3, savea4, savea5, savea6;
savea2 = EM_A2;
EM_A0 = (LONGINT) (long) US_TO_SYN68K(p);
EM_A1 = (LONGINT) (long) US_TO_SYN68K(STARH(h));
EM_A2 = (LONGINT) (long) US_TO_SYN68K(procp); /* for compatibility with above */
saved1 = EM_D1;
saved2 = EM_D2;
saved3 = EM_D3;
saved4 = EM_D4;
saved5 = EM_D5;
saved6 = EM_D6;
saved7 = EM_D7;
savea3 = EM_A3;
savea4 = EM_A4;
savea5 = EM_A5;
savea6 = EM_A6;
CALL_EMULATOR((syn68k_addr_t) (long) US_TO_SYN68K (procp));
EM_D1 = saved1;
EM_D2 = saved2;
EM_D3 = saved3;
EM_D4 = saved4;
EM_D5 = saved5;
EM_D6 = saved6;
EM_D7 = saved7;
EM_A3 = savea3;
EM_A4 = savea4;
EM_A5 = savea5;
EM_A6 = savea6;
retval = EM_D0;
EM_A2 = savea2;
} else
retval = fsDSIntErr;
if (routine == Open)
HxX(h, dCtlFlags) |= CWC(DRIVEROPENBIT);
else if (routine == Close) {
HxX(h, dCtlFlags) &= ~CWC(DRIVEROPENBIT);
HUnlock((Handle) h);
HUnlock((Handle) ramdh);
MBarEnable = 0;
/* NOTE: It's not clear whether we should zero out this
field or just check for DRIVEROPEN bit up above and never
send messages except open to non-open drivers. */
MR(UTableBase)[devicen].p = CLC(0);
}
if (routine < Close)
retval = CW(p->ioParam.ioResult); /* see II-193 */
}
}
fs_err_hook (retval);
return retval;
}
/* PBOpen, PBClose, PBRead and PBWrite are part of the file manager */
A2(PUBLIC, OSErr, PBControl, ParmBlkPtr, pbp, BOOLEAN, a) /* IMII-186 */
{
OSErr err;
err = ROMlib_dispatch(pbp, a, Ctl, 0);
fs_err_hook (err);
return err;
}
A2(PUBLIC, OSErr, PBStatus, ParmBlkPtr, pbp, BOOLEAN, a) /* IMII-186 */
{
OSErr err;
err = ROMlib_dispatch(pbp, a, Stat, 0);
fs_err_hook (err);
return err;
}
A2(PUBLIC, OSErr, PBKillIO, ParmBlkPtr, pbp, BOOLEAN, a) /* IMII-187 */
{
OSErr err;
pbp->cntrlParam.csCode = CWC(killCode);
err = ROMlib_dispatch(pbp, a, Ctl, 0);
fs_err_hook (err);
return err;
}
/*
* OpenDriver is defined below ROMlib_driveropen.
* CloseDriver is defined below ROMlib_driverclose.
*/
/* FSRead, FSWrite are part of the file manager */
A3(PUBLIC, OSErr, Control, INTEGER, rn, INTEGER, code,
Ptr, param) /* IMII-179 */
{
ParamBlockRec pb;
OSErr err;
pb.cntrlParam.ioVRefNum = 0;
pb.cntrlParam.ioCRefNum = CW(rn);
pb.cntrlParam.csCode = CW(code);
if (param)
BlockMove(param, (Ptr) pb.cntrlParam.csParam,
(Size) sizeof(pb.cntrlParam.csParam));
err = PBControl(&pb, FALSE);
fs_err_hook (err);
return err;
}
A3(PUBLIC, OSErr, Status, INTEGER, rn, INTEGER, code, Ptr, param) /* IMII-179 */
{
ParamBlockRec pb;
OSErr retval;
pb.cntrlParam.ioVRefNum = 0;
pb.cntrlParam.ioCRefNum = CW(rn);
pb.cntrlParam.csCode = CW(code);
retval = PBStatus(&pb, FALSE);
if (param)
BlockMove((Ptr) pb.cntrlParam.csParam, param,
(Size) sizeof(pb.cntrlParam.csParam));
fs_err_hook (retval);
return retval;
}
A1(PUBLIC, OSErr, KillIO, INTEGER, rn) /* IMII-179 */
{
ParamBlockRec pb;
OSErr err;
pb.cntrlParam.ioCRefNum = CW(rn);
err = PBKillIO(&pb, FALSE);
fs_err_hook (err);
return err;
}
A1(PUBLIC, DCtlHandle, GetDCtlEntry, INTEGER, rn)
{
int devicen;
devicen = -rn - 1;
return (devicen < 0 || devicen >= NDEVICES) ?
0
:
MR(MR(UTableBase)[devicen].p);
}
/*
* ROMlib_driveropen will be called by PBOpen if it encounters a name
* beginning with * a period.
*/
PUBLIC driverinfo *ROMlib_otherdrivers = 0; /* for extensibility */
PRIVATE driverinfo knowndrivers[] = {
#if defined (LINUX) || defined (NEXTSTEP) || defined (MSDOS) || defined (CYGWIN32)
{ ROMlib_serialopen, ROMlib_serialprime, ROMlib_serialctl,
ROMlib_serialstatus, ROMlib_serialclose, (StringPtr) "\004.AIn", -6, },
{ ROMlib_serialopen, ROMlib_serialprime, ROMlib_serialctl,
ROMlib_serialstatus, ROMlib_serialclose, (StringPtr) "\005.AOut", -7, },
{ ROMlib_serialopen, ROMlib_serialprime, ROMlib_serialctl,
ROMlib_serialstatus, ROMlib_serialclose, (StringPtr) "\004.BIn", -8, },
{ ROMlib_serialopen, ROMlib_serialprime, ROMlib_serialctl,
ROMlib_serialstatus, ROMlib_serialclose, (StringPtr) "\005.BOut", -9, },
#endif
};
A2(PUBLIC, OSErr, ROMlib_driveropen, ParmBlkPtr, pbp, /* INTERNAL */
BOOLEAN, a)
{
driverinfo *dip, *edip;
OSErr err;
INTEGER devicen;
umacdriverptr up;
DCtlHandle h;
ramdriverhand ramdh;
ResType typ;
BOOLEAN alreadyopen;
ZONE_SAVE_EXCURSION
(SysZone,
{
err = noErr;
if ((ramdh =
(ramdriverhand) GetNamedResource(TICK("DRVR"),
MR(pbp->ioParam.ioNamePtr)))) {
LoadResource((Handle) ramdh);
GetResInfo((Handle) ramdh, &devicen, &typ, (StringPtr) 0);
devicen = CW(devicen);
h = MR(MR(UTableBase)[devicen].p);
alreadyopen = h && (HxX(h, dCtlFlags) & CWC(DRIVEROPENBIT));
if (!h && !(h = MR(MR(UTableBase)[devicen].p =
RM((DCtlHandle) NewHandle(sizeof(DCtlEntry))))))
err = MemError();
else if (!alreadyopen) {
memset((char *) STARH(h), 0, sizeof(DCtlEntry));
HxX(h, dCtlDriver) = (umacdriverptr) RM(ramdh);
HxX(h, dCtlFlags) = HxX(ramdh, drvrFlags) | CWC(RAMBASEDBIT);
HxX(h, dCtlRefNum) = CW(- (devicen + 1));
HxX(h, dCtlDelay) = HxX(ramdh, drvrDelay);
HxX(h, dCtlEMask) = HxX(ramdh, drvrEMask);
HxX(h, dCtlMenu) = HxX(ramdh, drvrMenu);
if (HxX(h, dCtlFlags) & CWC(NEEDTIMEBIT))
HxX(h, dCtlCurTicks) = CL(TickCount() + Hx(h, dCtlDelay));
else
HxX(h, dCtlCurTicks) = CLC(0x7FFFFFFF);
/*
* NOTE: this code doesn't check to see if something is already open.
* TODO: fix this
*/
pbp->cntrlParam.ioCRefNum = HxX(h, dCtlRefNum);
err = ROMlib_dispatch(pbp, a, Open, 0);
} else
{
pbp->cntrlParam.ioCRefNum = HxX(h, dCtlRefNum);
err = noErr;
}
} else {
dip = 0;
if (ROMlib_otherdrivers) {
for (dip = ROMlib_otherdrivers; dip->open &&
!EqualString(dip->name, MR(pbp->ioParam.ioNamePtr), FALSE, TRUE);
dip++)
;
if (!dip->open)
dip = 0;
}
if (!dip) {
for (dip = knowndrivers, edip = dip + NELEM(knowndrivers);
dip != edip &&
!EqualString(dip->name, MR(pbp->ioParam.ioNamePtr), FALSE, TRUE);
dip++)
;
if (dip == edip)
dip = 0;
}
if (dip) {
devicen = -dip->refnum -1;
if (devicen < 0 || devicen >= NDEVICES)
err = badUnitErr;
else if (MR(UTableBase)[devicen].p)
err = noErr; /* note: if we choose to support desk */
/* accessories, we will have to */
/* check to see if this is one and */
/* call the open routine if it is */
else {
if (!(h = MR(MR(UTableBase)[devicen].p =
RM((DCtlHandle) NewHandle(sizeof(DCtlEntry))))))
err = MemError();
else {
memset((char *) STARH(h), 0, sizeof(DCtlEntry));
up = (umacdriverptr) NewPtr(sizeof(umacdriver));
if (!(HxX(h, dCtlDriver) = RM(up)))
err = MemError();
else {
up->udrvrOpen = (ProcPtr) RM(dip->open);
up->udrvrPrime = (ProcPtr) RM(dip->prime);
up->udrvrCtl = (ProcPtr) RM(dip->ctl);
up->udrvrStatus = (ProcPtr) RM(dip->status);
up->udrvrClose = (ProcPtr) RM(dip->close);
str255assign(up->udrvrName, dip->name);
err = noErr;
}
}
}
if (err == noErr) {
pbp->cntrlParam.ioCRefNum = CW(dip->refnum);
err = ROMlib_dispatch(pbp, a, Open, 0);
}
} else
err = dInstErr;
}
});
fs_err_hook (err);
return err;
}
A2(PUBLIC, OSErr, OpenDriver, StringPtr, name, INTEGER *, rnp) /* IMII-178 */
{
ParamBlockRec pb;
OSErr retval;
pb.ioParam.ioRefNum = CWC (0); /* so we can't get garbage for ioRefNum. */
pb.ioParam.ioPermssn = fsCurPerm;
pb.ioParam.ioNamePtr = RM(name);
retval = ROMlib_driveropen(&pb, FALSE);
*rnp = pb.ioParam.ioRefNum;
fs_err_hook (retval);
return retval;
}
A1(PUBLIC, OSErr, CloseDriver, INTEGER, rn) /* IMII-178 */
{
ParamBlockRec pb;
OSErr err;
pb.cntrlParam.ioCRefNum = CW(rn);
err = PBClose(&pb, FALSE);
fs_err_hook (err);
return err;
}