📄 cpmfs.hpp
字号:
//*************************************************************************// MODULE : CpmFs - A file system based on the old CP/M design *// AUTHOR : Ron Chernich *// PURPOSE: Provides reudimentary (nonhierarachial) file system for RCOS *// HISTORY: *// 13-AUG-94 First version *// 17-AUG-84 DskDrv header file merged *//*************************************************************************#ifndef __CPMFS__ #define __CPMFS__ #include "rcos.hpp" #include "kernel.hpp" #include "message.hpp" #define MAX_DRIVES 3 // No real limit, but A: B: C: will do.. class CpmFs; // forward reference to File System class CpmBdos; // forward reference for Dos array ///////////////////////////////////////////////////////////////////////// // structure describes salient physical characteristics of the // disk disk drive being modelled. // typedef struct DskParmsTag { UINT16 nSecs; // sectors per track UINT16 nTrks; // total cylinders on disk UINT16 nSides; // no of tracks per cylinder UINT16 nSecSize; // bytes per sector BYTE nAngleInc; // rotate speed (degrees per mS) BYTE nTrkInc; // track-to-track access time (mS) BYTE nSettle; // head settle adelay (mS) UINT32 nErrRate; // soft error rate (one every...) } DPB, *PDPB; ///////////////////// // This parameter list is equivalent to the Digital Research "MAC" // macro that was used to build the required logical disk parameters.. // typedef struct macTag { BYTE nLid; // Logical unit ID (0 = "A:" ...) BYTE nFsc; // first physical sector number (0 or 1) BYTE nLsc; // last sector number BYTE nSkf; // optional sector skew factor UINT16 nBls; // data allocation block size UINT16 nDks; // number of blocks on disk UINT16 nDir; // number of directory entreies UINT16 nCks; // number of "checked" directory entries (for exchangable media) BYTE nOfs; // track offset of logical track 00 } DPARAM, *PDPARAM; ////////////////// // As I remember it, the CP/M directory entries went something like this. // The m.s.b. of the name extension holds file attributes: // fextn[0] set = read only // 1 = system (hidden) // #define PNAME_LEN 8 #define ENAME_LEN 3 #define BLOCK_LEN 128 #define FILENAME_LEN (PNAME_LEN + ENAME_LEN) // typedef struct deTag { BYTE nUsrNmbr; // 0xe5 = erased, else user number (zero) char fname[PNAME_LEN]; // File name char fextn[ENAME_LEN]; // File extension BYTE nExtent; // logical extent of this entry BYTE nRes1; // internal usage BYTE nRes2; // internal usage BYTE nRcnt; // BLOCK_LEN byte record num in use in last block BYTE nAllocBlk[16]; // Disk blocks allocated to this extent } DIRENT, *PDIRENT; /////////////// // constants define all intermediate operations in the CpmBdos (below) // that are called via the CpmBdos::NxtFnc public member. // enum NXTFNC { LOG1, STAT1, CLOSE1, CLOSE2, OPEN1, OPEN2, CREAT1, CREAT2, CREAT3, READ0, READ1, WRITE0, WRITE1, WRITE2, FIND1, FIND2, RENAM1, RENAM2, REMOV1, REMOV2 }; ///////////// // Permissable high level commands for the Disk Units via their // "channel" controller. // enum CHCMD { DD_CALIBRATE, DD_READ, DD_WRITE, DD_FORMAT }; /////////////// // a CP/M File Control Block. While it "uses" the Directory entry struct, // certain bytes have different meanings from those held on the disk. // Note that the target buffer for the transfer is an extension of the // original - added to permit totally encapsulated operation requests. // typedef struct fcbTag { DIRENT de; // A.A. but nUsrNmbr = drive ID BYTE nCurRec; // current record for sequential read/write BYTE nRandom[3]; // record number (0..65535) char *pBuf; // address for transfer } FCB, *PFCB; ////////////////// // We plan to pass references to FCB's around using the asynchronous // "post" mechanism, but this ends up "deleteing" the passed object // if passed by reference, so this little double indirection thingy // preserves the FCB (as far as TxPost is concerned) but allows the // class <CpmDbos> to make changes back to the referenced item.. // typedef struct fcbRefTag { PFCB pFcbRef; } FCBREF, *PFCBREF; /////////////// // A "Transfer Request" class; being an object created for each quantum // of disk activity. It gets posted to the appropriate drive unit and // enters its FIFO queue. When actioned, the CpmBdos pointer is used // to call the member function that knows (via a constant placed in the // object by the previous member function) which member function to pass // the object along to next. // // Normally, the <pDma> pointer will be a copy of the buffer address in // the FCB, but making it separate allows the BDOS to present the disk // driver with the address of its internal buffers without danger of the // user code accidentally gaining access to them. // // Note: stuff which class <DskModel> is not concerned with // is hidden away - including C::tor and D::tor. // class XfReq { friend CpmFs; friend CpmBdos; protected: PFCB pFcb; // instance of an FCB in the PCB or BDOS NXTFNC ivec; // what to do next (internal to CpmBdos) BYTE nRetry; // error retry count XfReq *pNxt; // any "postponed" assosociated Xfer ~XfReq (void) { } // only friends can destroy XfReq (UINT16 = 0); // or create one of these.. XfReq (UINT16, PFCB); public: UINT16 uProc; // transfer initiator PID (or BDOS ID) CHCMD cmnd; // What we want the disk channel to do UINT16 nTrk, nSec, nSid; // Cylinder, sector, head char *pDma; // transfer buffer pointer BOOL bRes; // Outcome of channel operation CpmBdos *pFnCb; // class that handeles completed xfers }; ///////////////////////////////////////////////////////////////////// // Interface to the file system based on our old friend, the "port". // Note how each file system operation takes a single XfReq pointer as // input. The Single instance of class CpmFs receives requests for // FS operations from user processes as messages. It merely creates // a new XfReq object, filling in the originating PID and FCB pointer, // determines which disk "unit" the request is for, checks that that // unit is "on-line" and then calls the appropriate (protected) member // function. // // ALL calls to the File System result in the caller process // becomming blocked. When the FS service is deemed to be complete, // a result message will be posted to the PID (unblocking it) and the // XfReq object killed off. The last member function of CpmBdos to // be passed the XfReq pointer does this. // // Note: it's each user process's responsibility to ensure the FCB // is correctly initialised (by a successful call to FsOpen or FsCreat). // The FS uses these FCB's to retain working data during file I/O // operations. Looks to me now (in hindsight) that if you diddle with // these, and you can trash the file system, big time. Funny, I don't // recall that ever happening though (?) // class CpmFs : public port { private: CpmBdos *pUnit[MAX_DRIVES]; // Disk File System instances public: CpmFs (UINT16, UINT16, Knl*); // register with kernel ~CpmFs (void); // murder all file systems void RxPort (PMSG); // supply virtual member of "port" void MountDrive (UINT16, char, DPB&, DPARAM&); // Instatiate new Bdos }; /////////////////////////////////////////////////////////////////////// // Here is the actual, re-entrant File System class. In olden days // (BC++), we would write this as a set of subroutines with lists and // arrays to hold dynamic, unit variable data. To-day, we make it a // class and instantiate it once for each physical disk configured in. // A more flexible scheme would have a list of devices rather than a // simple array (as used in class CpmFs) permitting unlimited, dynamic // mount and un-mount of devices at run time. // // Once a physical disk is determined to be "on-line" (ie, the host file // emulating a disk unit, or a real disk unit, even, has started up ok), // an instance of this class is created giving it the disk characteristics // and some required file system parameters (number of directory entries, // block size, etc..). It is also given the Kernel message dispatcher // address and the ID of the disk unit it will be responsible for. // // The sequence of events then goes like this: // 1. A process invokes an FS operation and is blocked. This results in // a message to the CpmFs instance. // 2. The <CpmFs> creates an XfReq instance, fills in the FCB and PID
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -