--- /dev/null
+// Author: Chris Somers\r
+\r
+AJR:\r
+ This file contains 3 .h files and two .c files, and some notes\r
+ all glued together. you'll have to cut them apart to compile.\r
+\r
+// Author: Chris Somers\r
+\r
+To use memory.c, a few notes are in order. This file was originally used\r
+in an event-driven windowing environment, so there are several headers you\r
+won't need (so I didn't include 'em).\r
+\r
+AJR - I nuked all uneeded references from the code\r
+\r
+This code was written for Borland C/C++ v3.1 and has _not_ been tested\r
+under any other version. The first set of conventional memory calls\r
+(those flanked by #ifndef USEBORLIB) are to replace Borland's malloc\r
+library when using 3rd party libraries or APIs which called DOS's malloc.\r
+Add a -DUSEBORLIB to the compile command line to remove this code.\r
+\r
+The file, tasks.h (application specific - not included), optionally\r
+#define'd EMM_SUPPORT and TCPCOM. #define the first and not the second.\r
+\r
+AJR - I modified these sources so this isn't neccessary - all\r
+ references to TCPCOM have been deleted.\r
+\r
+Add memory.p to your application to have access to the EMM calls. Don't\r
+include memory.h - it's got static calls and variables you don't want\r
+direct access to.\r
+\r
+AJR - I added memory.p to memory.c, and cleaned up memory.h so it can\r
+ be included.\r
+\r
+ Please see emm.c for an example.\r
+\r
+returns.h and sizes.h just have the #defines for (duh!) return codes\r
+and size constants. Unfortunately, the values used for some of the\r
+return codes may not be safely changed. If they clash with codes in your\r
+program, it might be safer to rename them than to change their values\r
+and try to see where the EMM code got broken.\r
+\r
+AJR: I renamed returns.h to emmret.h and sizes.h to emmsize.h\r
+ to avoid file name clashes.\r
+\r
+Here are some notes on the calls:\r
+\r
+OpenEMM() - call this first, period.\r
+CloseEMM() - call this last. It'll even free any EMS you forgot to free\r
+ in your program (this isn't like conventional memory, y'know)\r
+EMMInstalled() - returns TRUE or FALSE. Use only after OpenEMM() is called.\r
+EMMalloc() - returns a pointer to the first EMM page (EMMSeg:0000 hex).\r
+ Also stuffs a new handle into *Handle (*Handle == NULL is not\r
+ checked for, so be careful or fix the code). You gotta supply\r
+ Pages (i.e. number of 16K blocks).\r
+EMMRealloc() - increases/decreases number of pages allocated to your handle.\r
+EMMFree() - frees all the pages and voids the handle.\r
+MapEMM() - places 1 to 4 Pages into the page frame starting with page, Start.\r
+UnmapEMM() - removes the pages from the page frame so nothing else trashes\r
+ your data.\r
+UseEMM() - same as MapEMM() but saves the frame state before mapping.\r
+SaveEMM() - same as UnmapEMM() but restores a saved frame state after unmapping.\r
+EMMCoreLeft() - returns the number of bytes of EMM left to allocate.\r
+\r
+The comments in the MapEMM() and UseEMM() (and UnmapEMM() and SaveEMM()) speak\r
+of 'applications' and 'devices'. These refer to layers in the development\r
+environment using this .c file. The application layer could use EMS as long\r
+as it kept track of it's own usage. So it wouldn't have to keep track of the\r
+environment's usage, 'devices' (i.e. lower layers) saved the page frame\r
+state to use EMS themselves, so as not to trash the application layer's data,\r
+and restored the original state upon returning.\r
+\r
+\r
+\r
+More notes:\r
+Alexander J Russell wrote:\r
+\r
+>How do you USE emm memory?\r
+>With xms it is obvious - you copy mem back and forth.\r
+>What the parameters for mapemm() etc... mean isn't documented well enough\r
+>for a newbie to use it.\r
+\r
+EMM is alot like XMS except that the EMM driver does the copying for you,\r
+without really copying (the 386's LDTs are used to point to appropriate\r
+parts of physical memory when mapping EMM). Here's how it works.\r
+EMM has a 64K (typically) page frame in conventional memory, often at\r
+E000-EFFF. The page frame consists of four 16K pages. When you call\r
+EMMalloc(), you supply the number of 16K pages you need and it\r
+returns 1) a handle, and 2) a pointer to the page frame (i.e. E000:0000).\r
+This memory is allocated somewhere in extended memory but still\r
+unavailable. To use it, you must 'map' it into the page frame so\r
+conventional memory pointers can access it. The MapEMM() function\r
+maps the pages you need (up to four) associated with that handle \r
+into the page frame. You can now use your alloc'd memory at E000.\r
+When you're finished accessing the memory, you can unmap it using\r
+UnmapEMM(). This removes the mapping from the page frame so you can\r
+map other allocations or just protect what you've already written\r
+(i.e. writing to the page frame segment won't touch your data).\r
+N.B. You never *have to* unmap your pages. Mapping new pages\r
+automagically unmaps existing mappings - but it's good practice\r
+to unmap when you're finished.\r
+\r
+Another way to look at EMS is to consider the page frame as a window\r
+over the extended memory area. Mapping is like moving the window to\r
+some area of XMS and making it available with a conventional memory\r
+pointer - at the page frame address, which never changes. \r
+In other words, EMS 'bank switches' segments of XMS memory into\r
+conventional memory.\r
+\r
+>I think I call openemm() the use map and unmap to utilize the mem.\r
+>what does map do, what do the parms mean? Once mapped how is the mem used.\r
+\r
+Pretty close. OpenEMM() makes sure the driver is loaded and gets the\r
+page frame address (EMMSeg:0000). Then EMMalloc() reserves the specified\r
+number of 16K pages, associates them to a handle, and gives your app the\r
+page frame address. Then MapEMM() lets you use up to four pages at a time\r
+(at the address returned by EMMalloc()). The parameters for MapEMM() are:\r
+- the handle you got from EMMalloc()\r
+- the memory page # to map to the first page frame page.\r
+- the number of pages to map to the page frame (max. of 4)\r
+BTW, all numbering is zero-based.\r
+\r
+>Could you send a quick overview of how you actually use emm mem in a dos\r
+>program.\r
+\r
+ -------------------- see emm.c for example ---------------\r
+\r
+\r
+>Can I re-post your code and notes on my page?\r
+Yup. Leaving my name in the comments at the top would be much appreciated.\r
+\r
+I learnt most of this from DOS Programmer's Reference by Terry Dettmann\r
+from Que publishing (it's (C)1989 and I *still* use it!). You can check out\r
+other references dealing with int67h (the EMS API) too.\r
+\r
+Hope I didn't leave anything out. Email me again if any points aren't clear.\r
+\r
+Chris S.\r
+\r
+AJR adds:\r
+\r
+memory.c, and the h files all you need to use emm!\r
+emm.c is just a test program to show how it is used.\r
+\r
+\r
+/*\r
+ *********************************************************************\r
+ *********************************************************************\r
+\r
+ next file\r
+\r
+ *********************************************************************\r
+ *********************************************************************\r
+*/\r
+\r
+// Cut this out as emmsize.h\r
+\r
+/* File: EmmSize.h\r
+ * Module: All Modules\r
+ * Author(s): Chris Somers\r
+ * Date: May 8, 1992\r
+ * Version: V.1.0\r
+ */\r
+\r
+#ifndef _EMMSIZES_DEF\r
+#define _EMMSIZES_DEF 1\r
+\r
+\r
+/* Module size constants */\r
+\r
+#define MAXACTIONS 29\r
+#define MAXCHANNELS 4\r
+#define MAXFOCUS 3\r
+#define MAXBUFTYPES 64\r
+#define MAXEMHANDLES 64 /* up to a max of 255 */\r
+#define MAXTIMERS 32\r
+#define MAXTITEMS 128\r
+#define MAXQUEUES 24\r
+#ifdef PRINTER\r
+#define MAXPRNS 4\r
+#else\r
+#define MAXPRNS 0\r
+#endif\r
+#ifdef UTSCOM\r
+#define MAXUTSSCRNS 2\r
+#else\r
+#define MAXUTSSCRNS 0\r
+#endif\r
+#ifdef CAPTURE\r
+#define MAXCAPTURE 1\r
+#else\r
+#define MAXCAPTURE 0\r
+#endif\r
+#define MAXIRQS 10\r
+#define MAXTCPDSCPTITEMS 16 /*max # of TCP connections*/\r
+\r
+#define FREEBUFF 1 /* CallIODevice flag for BuffSize arrays */\r
+#define DSCONLY 2 /* allocate a BufDscpt, only - no buffer */\r
+\r
+#define EMMPAGESIZE 0x4000 /* 16K EMM page size */\r
+#define SETUPLEN 32\r
+#define NAMELEN 40\r
+#define UNIXLEN 32\r
+#define ADDRLEN 16\r
+#define TITLELEN 128\r
+#define TSLEN 80\r
+#define COMMENTLEN 65\r
+#define PALSIZE 768\r
+#define QSTRLEN 254\r
+#define PRNBUFSIZ 2048\r
+#define TXTSCRNSIZE 4096\r
+#define UTSBUFSIZ 4096\r
+#define UTSSCRNSIZ 1920\r
+#define QMEMSIZE 15\r
+#define KBUFLEN 16\r
+#define GXBUFFSIZE 0x4000\r
+#define TCPNDBUFFSIZE 0x1000 /*router auto-allocation buff size*/\r
+ /* graphics printing scale values */\r
+#define SCALE_HALF 1 /* value must not change */\r
+#define SCALE_ONE 2\r
+#define SCALE_QUART 3 /* value must not change */\r
+\r
+#define SIXTH_SECOND 3L /* shade over 1/6 of a second*/\r
+#define HALF_SECOND 9L\r
+#define ONE_SECOND 18L\r
+#define TWO_SECONDS 36L\r
+#define FIVE_SECONDS 91L\r
+#define TEN_SECONDS 182L\r
+#define HALF_MINUTE 182*3L /* same as 18.2*30, right? */\r
+#define ONE_MINUTE 182*6L /* same as 18.2*60, right? */\r
+#define TWO_MINUTES 182*12L /* same as 18.2*120, right? */\r
+#define FIVE_MINUTES 182*30L /* same as 18.2*300, right? */\r
+#define TEN_MINUTES 182*60L /* same as 18.2*600, right? */\r
+#define HALF_HOUR 182*180L /* same as 18.2*1800, right? */\r
+#define ONE_HOUR 182*360L /* same as 18.2*3600, right? */\r
+\r
+#define MAXROUTMOVES 24 /*max # of routing moves at one time*/\r
+ /*also max # of Move Complete Events*/\r
+/* Event Channel Defines */\r
+\r
+#define MAXRECALLEVENTS 1 /*max nm of Recall Event Channels*/\r
+#define MAXKBDEVENTS 1 /*max nm of Kbd Event Channels*/\r
+#define MAXPRNEVENTS 4 /*max nm of Prt Prog & Prt Cmplte Event Chan*/\r
+#define MAXUTSRCVEVENTS MAXUTSSCRNS /*max nm of Uts Rx Event Chans*/\r
+#define MAXUTSXMTEVENTS MAXUTSSCRNS /*max nm of Uts Tx Event Chans*/\r
+#define MAXCAPEVENTS 2 /* max number of capture event channels */\r
+#define MAXOP1CMPLTEVENTS 1 /*max nm of Operation 1 Cmplt Event Channels*/\r
+#define MAXOP2CMPLTEVENTS 1 /*max nm of Operation 2 Cmplt Event Channels*/\r
+#define MAXOP3CMPLTEVENTS MAXTCPDSCPTITEMS /*max nm of Op 3 Event Chans*/\r
+#define MAXTCPEVENTS MAXTCPDSCPTITEMS /* max nm of TCP Event types */\r
+\r
+#endif\r
+\r
+/*\r
+ *********************************************************************\r
+ *********************************************************************\r
+\r
+ next file\r
+\r
+ *********************************************************************\r
+ *********************************************************************\r
+*/\r
+\r
+// AJR notes: some of these are not used by the emm code\r
+\r
+// Cut this out as emmret.h\r
+\r
+/* File: EmmRet.h\r
+ * Module: All Modules\r
+ * Author(s): Chris Somers\r
+ * Date: May 8, 1992\r
+ * Version: V.1.0\r
+ */\r
+\r
+#ifndef _EMM_RETURNS_DEF\r
+#define _EMM_RETURNS_DEF 1\r
+\r
+/* Module return values */\r
+\r
+/* Return Values */\r
+\r
+#define START 8\r
+#define END 7\r
+#define MOVABORT 6\r
+#define PRN_COMPLETE 5\r
+#define PRN_PROGRESS 4\r
+#define INCOMPLETE 3\r
+#define HAVEROOM 2\r
+#define SUCCESS 1\r
+#define TRUE 1\r
+#define YES 1\r
+#define FALSE 0\r
+#define NO 0\r
+#define NOTREADY 0\r
+#define NO_DATA 0\r
+#define NONE -1\r
+\r
+/* Start of Recoverable error codes */\r
+\r
+#define NO_SPACE -1001\r
+#define NOTPOLLING -1002\r
+#define ALREADYDONE -1003\r
+#define NO_PRN_DEV -1004\r
+#define OUTF_PAPER -1005\r
+#define NO_VIDEO -1006\r
+#define TIMEOUT -1007\r
+#define FILENOPEN -1008\r
+#define ABORT_REQ -1009\r
+#define DEV_IOERR -1010\r
+\r
+#define MAXRERR 10\r
+#define RECOVERABLE -1999 /* all above errors are recoverable */\r
+\r
+/* Start of Threadfatal error codes */\r
+\r
+#define NOT_OPEN -2001\r
+#define NOT_ATTACHED -2002\r
+#define NO_CONNECTION -2003\r
+#define INSUFF_MEM -2004\r
+#define NR_TIMEOUT -2005\r
+\r
+#define MAXTERR 5\r
+#define THREADFATAL -2999 /* above errors force task to cancel */\r
+\r
+/* Start of Systemfatal error codes */\r
+\r
+#define BAD_TASKNUM -3001\r
+#define BAD_HANDLE -3002\r
+#define BAD_HARDWARE -3003\r
+#define INVALIDACTION -3004\r
+#define NOFREEITEMS -3005\r
+#define NO_MEMORY -3006\r
+#define NO_EMS -3007\r
+#define VALUE_OUTF_RANGE -3008\r
+#define BAD_MODE -3009\r
+#define NO_PALETTE -3010\r
+#define BAD_DISPPAGE -3011\r
+#define NO_TSR -3012\r
+#define BUFTOOSMALL -3013\r
+#define BAD_NAME -3014\r
+#define BAD_DISPHW -3015\r
+#define NO_FLOPPY -3016\r
+\r
+#define MAXSERR 16\r
+#define SYSTEMFATAL -3999 /* above errors are fatal to system */\r
+\r
+#endif\r
+\r
+/*\r
+ *********************************************************************\r
+ *********************************************************************\r
+\r
+ next file\r
+\r
+ *********************************************************************\r
+ *********************************************************************\r
+*/\r
+\r
+// Cut this out as memory.h\r
+\r
+/* File: Memory.h\r
+ * Module: All Modules\r
+ * Author(s): Chris Somers\r
+ * Date: August 5, 1993\r
+ * Version: V.1.1\r
+\r
+ modified by Alex Russell to simplify.\r
+ */\r
+\r
+\r
+#ifndef _MEMORY_DEF\r
+#define _MEMORY_DEF 1\r
+\r
+#include "emmret.h"\r
+#include "emmsize.h"\r
+\r
+#define CMM 0\r
+#define EMM 1\r
+\r
+extern int OpenEMM(void);\r
+extern void CloseEMM(void);\r
+extern int EMMInstalled(void);\r
+extern void far *EMMalloc(int *Handle, int Pages);\r
+extern int EMMRealloc(int Handle, int Pages);\r
+extern void EMMFree(int Handle);\r
+extern int MapEMM(int Handle, int Start, int Pages);\r
+extern void UnmapEMM(int Handle, int Start, int Pages);\r
+extern int UseEMM(int Handle, int Start, int Pages);\r
+extern void SaveEMM(int Handle, int Start, int Pages);\r
+extern unsigned long EMMCoreLeft(void);\r
+\r
+#endif\r
+\r
+/*\r
+ *********************************************************************\r
+ *********************************************************************\r
+\r
+ next file\r
+\r
+ *********************************************************************\r
+ *********************************************************************\r
+*/\r
+\r
+\r
+/* File: Memory.c\r
+ * Module: All Modules\r
+ * Author(s): Chris Somers\r
+ * Date: December 1, 1992\r
+ * Version: V.1.1\r
+\r
+ minor mods by Alex Russell to simplify\r
+\r
+ Must use memory model with FAR code\r
+\r
+ */\r
+\r
+\r
+\r
+#if !defined(__LARGE__) && !defined(__COMPACT__) && !defined(__HUGE__)\r
+#error Invalid memory model for compiling MEMORY.C\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <dos.h>\r
+#include <mem.h>\r
+\r
+#include "memory.h"\r
+\r
+// static globals --------------------------------\r
+\r
+static int ActiveEMList[MAXEMHANDLES];\r
+static unsigned int EMMSeg;\r
+\r
+// forward declarations ---------------------------------\r
+\r
+static int EMPresent(void);\r
+static int EMReady(void);\r
+static unsigned int GetEMMSeg(void);\r
+static int GetEMHandle(int NumPages);\r
+static int EMMap(int Handle, int LogPg, int PhyPg);\r
+static int FreeEMHandle(int Handle);\r
+static int GetNumPages(int Handle);\r
+static int EMStateSave(int Handle);\r
+static void EMStateRestore(int Handle);\r
+\r
+\r
+/********************************************************************/\r
+int\r
+OpenEMM(void)\r
+{\r
+ if (!EMPresent() || !EMReady()) return(NOTREADY);\r
+ if (!(EMMSeg = GetEMMSeg())) return(NOTREADY); /*lint !e720 */\r
+ return(SUCCESS);\r
+} /* End of OpenEMM() */\r
+\r
+/********************************************************************/\r
+\r
+void\r
+CloseEMM(void)\r
+{\r
+ int i;\r
+\r
+ if (!EMMSeg) return;\r
+ for (i = 0; i < MAXEMHANDLES; i++) {\r
+ if (ActiveEMList[i]) {\r
+ FreeEMHandle(ActiveEMList[i]);\r
+ ActiveEMList[i] = 0;\r
+ }\r
+ }\r
+ EMMSeg = 0;\r
+} /* End of CloseEMM() */\r
+\r
+/********************************************************************/\r
+\r
+int\r
+EMMInstalled(void)\r
+{\r
+ return((EMMSeg) ? TRUE : FALSE); /* successfully opened? */\r
+} /* End of EMMInstalled() */\r
+\r
+/********************************************************************/\r
+\r
+unsigned long\r
+EMMCoreLeft(void)\r
+{\r
+ unsigned Pages;\r
+ unsigned long RtnVal = 0UL;\r
+\r
+ _asm {\r
+ mov ah,0x42 /* get EMM free page count */\r
+ int 0x67\r
+ or ah,ah\r
+ js InternalError /* returns 80, 81, or 84 hex on error */\r
+ mov Pages,bx /* number of unallocated 16K pages */\r
+ }\r
+ RtnVal = ((unsigned long)Pages << 14); /* Pages * 16K rtns bytes*/\r
+\r
+InternalError:\r
+\r
+ return(RtnVal);\r
+} /* End of EMMCoreLeft() */\r
+\r
+/********************************************************************/\r
+\r
+void far *\r
+EMMalloc(int *Handle, int Pages)\r
+{\r
+ int i;\r
+ char *RtnPtr = NULL;\r
+\r
+ if (!EMMSeg) {\r
+ *Handle = NOTREADY;\r
+ return(NULL);\r
+ }\r
+ if ((Pages < 1) || (Pages > 1020)) {\r
+ *Handle = VALUE_OUTF_RANGE;\r
+ return (NULL);\r
+ }\r
+ for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i]); i++) ;\r
+ if (i == MAXEMHANDLES) {\r
+ *Handle = NOFREEITEMS;\r
+ return (NULL);\r
+ }\r
+ if ((ActiveEMList[i] = GetEMHandle(Pages)) > 0) {\r
+ RtnPtr = MK_FP(EMMSeg, 0);\r
+ }\r
+ *Handle = ActiveEMList[i];\r
+ return((void far *)RtnPtr);\r
+} /* End of EMMalloc() */\r
+\r
+/********************************************************************/\r
+\r
+int\r
+EMMRealloc(int Handle, int Pages)\r
+{\r
+ int RtnCode = FALSE;\r
+\r
+ if (!EMMSeg || (Pages < 0) || (Pages > 1020)) {\r
+ return (FALSE);\r
+ }\r
+ _asm {\r
+ mov ah,0x51 /* change # of pages */\r
+ mov bx,Pages\r
+ mov dx,Handle\r
+ int 0x67\r
+ or ah,ah\r
+ js NoGo /* returns 80 to 88 hex on error */\r
+ }\r
+ RtnCode = TRUE;\r
+\r
+NoGo:\r
+\r
+ return(RtnCode);\r
+} /* End of EMMRealloc() */\r
+\r
+/********************************************************************/\r
+\r
+void\r
+EMMFree(int Handle)\r
+{\r
+ int i, j;\r
+\r
+ if (!EMMSeg) return;\r
+ for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ;\r
+ if (i >= MAXEMHANDLES) return;\r
+ j = 16;\r
+ while (j--) {\r
+ if (FreeEMHandle(ActiveEMList[i])) break;\r
+ }\r
+ ActiveEMList[i] = 0;\r
+} /* End of EMMFree() */\r
+\r
+/********************************************************************/\r
+\r
+int /* EMM map for application */\r
+MapEMM(int Handle, int Start, int Pages)\r
+{\r
+ int i;\r
+\r
+ if (!EMMSeg) return(NOTREADY);\r
+ for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ;\r
+ if (i == MAXEMHANDLES) return (NO_DATA);\r
+ if ((GetNumPages(Handle) < Pages) || (Pages < 1) || (Pages > 4)) {\r
+ return (VALUE_OUTF_RANGE);\r
+ }\r
+ for (i = Start; i < Start + Pages; i++) {\r
+ if (!EMMap(Handle, i, i - Start)) return(NO_DATA);\r
+ }\r
+ return(SUCCESS);\r
+} /* End of MapEMM() */\r
+\r
+/********************************************************************/\r
+\r
+void /* EMM unmap for application */\r
+UnmapEMM(int Handle, int Start, int Pages)\r
+{\r
+ int i, j;\r
+\r
+ if (!EMMSeg) return;\r
+ for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ;\r
+ if (i == MAXEMHANDLES) return;\r
+ j = Start + Pages;\r
+ if ((Pages < 1) || (j > 4)) return;\r
+\r
+ for (i = Start; i < j; i++) {\r
+ EMMap(Handle, NONE, i);\r
+ }\r
+} /* End of UnmapEMM() */\r
+\r
+/********************************************************************/\r
+\r
+int /* EMM map for devices - saves EMM state */\r
+UseEMM(int Handle, int Start, int Pages)\r
+{\r
+ EMStateSave(Handle);\r
+ return(MapEMM(Handle, Start, Pages));\r
+} /* End of UseEMM() */\r
+\r
+/********************************************************************/\r
+\r
+void /* EMM unmap for devices - restores EMM state */\r
+SaveEMM(int Handle, int Start, int Pages)\r
+{\r
+ UnmapEMM(Handle, Start, Pages);\r
+ EMStateRestore(Handle);\r
+} /* End of SaveEMM() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+EMPresent(void)\r
+{\r
+ int i, Segment;\r
+ char EMName[] = "EMMXXXX0";\r
+ char *s, *t;\r
+\r
+ _asm { /* can be replaced with getvect() */\r
+ push es\r
+ mov ax,0x3567 /* get vector for int 67h */\r
+ int 0x21\r
+ mov ax,es\r
+ mov Segment,ax\r
+ pop es\r
+ }\r
+ t = MK_FP(Segment, 0x0A); /* point to driver name */\r
+ s = EMName;\r
+ for (i = 0; (i < 8) && (*s++ == *t++); i++) ; /* strncmp equivalent */\r
+\r
+ if (i == 8) return(TRUE);\r
+ return(FALSE);\r
+} /*End of EMPresent() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+EMReady(void)\r
+{\r
+ _asm {\r
+ mov ah,0x40 /* get EM Manager Status */\r
+ int 0x67\r
+ or ah,ah\r
+ jns Ready /* returns 80, 81, or 84 hex on error */\r
+ }\r
+ return(FALSE);\r
+\r
+Ready:\r
+ return(TRUE);\r
+} /* End of EMReady() */\r
+\r
+/********************************************************************/\r
+\r
+static unsigned int\r
+GetEMMSeg(void)\r
+{\r
+ unsigned int EMSegment;\r
+\r
+ _asm {\r
+ mov ah,0x41 /* get EMM page frame segment */\r
+ int 0x67\r
+ or ah,ah\r
+ js NotReady /* returns 80, 81, or 84 hex on error */\r
+ mov EMSegment,bx\r
+ }\r
+ return(EMSegment); /*lint !e530 */\r
+\r
+NotReady:\r
+ return(NOTREADY);\r
+} /* End of GetEMMSeg() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+GetEMHandle(int NumPages)\r
+{\r
+ int NewHandle;\r
+\r
+ _asm {\r
+ mov ah,0x43 /* get handle and allocate EM */\r
+ mov bx,NumPages /* number of 16K pages to allocate */\r
+ int 0x67\r
+ or ah,ah /* returns 80 to 89 hex on error */\r
+ js NoHandle\r
+ mov NewHandle,dx /* retrieve handle */\r
+ }\r
+ return(NewHandle);\r
+\r
+NoHandle:\r
+ return(NO_DATA);\r
+} /* End of GetEMHandle() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+EMMap(int Handle, int LogPg, int PhyPg)\r
+{\r
+ int RtnCode = NO_DATA;\r
+\r
+ _asm {\r
+ mov ax,PhyPg /* physical page: 0 - 3 in AL only */\r
+ mov ah,0x44 /* map logical to physical page */\r
+ mov bx,LogPg /* logical page: 0 - 1020 */\r
+ mov dx,Handle\r
+ int 0x67\r
+ or ah,ah /* returns 80 to 8B hex on error */\r
+ js NoMapping\r
+ }\r
+ RtnCode = SUCCESS;\r
+\r
+NoMapping:\r
+ return(RtnCode);\r
+} /* End of EMMap() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+FreeEMHandle(int Handle)\r
+{\r
+ _asm {\r
+ mov ah,0x45 /* free handle and deallocate EM */\r
+ mov dx,Handle\r
+ int 0x67\r
+ or ah,ah /* returns 80 to 86 hex on error */\r
+ js NotFreed\r
+ }\r
+ return(SUCCESS);\r
+\r
+NotFreed: /* must retry if unsuccessful */\r
+ return(NO_DATA);\r
+} /* End of FreeEMHandle() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+GetNumPages(int Handle)\r
+{\r
+ int NumPages = 0;\r
+\r
+ _asm {\r
+ mov ah,0x4C /* get allocated pages for Handle */\r
+ mov dx,Handle\r
+ int 0x67\r
+ or ah,ah /* returns 80 to 84 hex on error */\r
+ js BadHandle\r
+ mov NumPages,bx\r
+ }\r
+BadHandle:\r
+\r
+ return(NumPages);\r
+} /* End of GetNumPages() */\r
+\r
+/********************************************************************/\r
+\r
+static int\r
+EMStateSave(int Handle)\r
+{\r
+ int RtnCode = NO_MEMORY;\r
+ _asm {\r
+ mov ah,0x47 /* save page map under Handle */\r
+ mov dx,Handle\r
+ int 0x67\r
+ or ah,ah\r
+ js Unsaved /* out of save space error */\r
+ }\r
+ RtnCode = SUCCESS;\r
+\r
+Unsaved:\r
+ return(RtnCode);\r
+} /* End of EMStateSave() */\r
+\r
+/********************************************************************/\r
+\r
+static void\r
+EMStateRestore(int Handle)\r
+{\r
+ _asm {\r
+ mov ah,0x48 /* restore page map for Handle */\r
+ mov dx,Handle\r
+ int 0x67 /* ignore error */\r
+ }\r
+} /* End of EMStateRestore() */\r
+\r
+/********************************************************************/\r
+\r
+/*\r
+ *********************************************************************\r
+ *********************************************************************\r
+\r
+ next file\r
+\r
+ *********************************************************************\r
+ *********************************************************************\r
+*/\r
+\r
+// Cut this out as emm.c\r
+\r
+/* File: emm.c\r
+ * Module: All Modules\r
+ * Author(s): Chris Somers\r
+ * Date: December 1, 1992\r
+ * Version: V.1.1\r
+\r
+ minor mods by Alex Russell to simplify\r
+\r
+ Must use memory model with FAR code\r
+\r
+ */\r
+\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <mem.h>\r
+\r
+#include "memory.h"\r
+\r
+void TransformData(char *pEmmData, unsigned int len)\r
+{\r
+ while ( len )\r
+ {\r
+ (*pEmmData)++;\r
+ pEmmData++;\r
+\r
+ len--;\r
+ }\r
+}\r
+\r
+void main(void)\r
+{\r
+ char *pEmmData;\r
+ int hEData;\r
+\r
+ if ( OpenEMM() != SUCCESS )\r
+ { // make sure we got EMM\r
+ printf("EMM unavailable.\n");\r
+ exit(1);\r
+ }\r
+ else\r
+ printf("Emm available\n");\r
+\r
+ pEmmData = EMMalloc(&hEData, 6); // get 6 * 16K bytes - 96K\r
+ if ( pEmmData == NULL )\r
+ {\r
+ printf("Not enough EMM or out of handles.\n");\r
+ exit(2);\r
+ }\r
+ else\r
+ printf("emm alloced OK\n");\r
+\r
+\r
+ printf("Map 1st 4 pages\n");\r
+ MapEMM(hEData, 0, 4); // load 1st 4 pages into page frame: 0-3\r
+\r
+ memset(pEmmData, 0x0e, 64000u);\r
+ UnmapEMM(hEData, 0, 4); // not absolutely necessary\r
+ \r
+ printf("Map next 2 pages\n");\r
+ MapEMM(hEData, 4, 2); // map last 2 pages: 4-5\r
+ memset(pEmmData, 0x0e, 32768u);\r
+\r
+ MapEMM(hEData, 0, 4);\r
+ // do some stuff with the first 64K of file data.\r
+ printf("Transform data\n");\r
+ TransformData(pEmmData, 64000UL);\r
+ MapEMM(hEData, 4, 2); // only unmaps 1st two pages of prior 64k mapping\r
+ // do stuff with remaining 32K of data\r
+ TransformData(pEmmData, 32768UL);\r
+ UnmapEMM(hEData, 0, 4); // should unmap before freeing\r
+\r
+ printf("Close emm\n");\r
+ EMMFree(hEData); // finished with the file data\r
+ CloseEMM();\r
+}\r
+\r
--- /dev/null
+This file contains 3 files:\r
+xmem.h : c include file\r
+xmem.asm : low level basic XMS acess\r
+xmemc.c : super easy C access via functions like fopen, fread, fwrite\r
+ xopen, xread, xwrite, xseek etc...\r
+\r
+FOR DOS REAL mode programs, requires HIMEM.SYS to be loaded in\r
+config.sys.\r
+\r
+XMEM.H ------------- START --------------------------------------------------\r
+#if !defined(_XMEM_H)\r
+#define _XMEM_H\r
+\r
+typedef struct xms_node\r
+ {\r
+ long start, size, off;\r
+ short used;\r
+ struct xms_node *next;\r
+ }\r
+xms_node_t;\r
+\r
+typedef struct\r
+ {\r
+ int handle;\r
+ unsigned long total;\r
+ unsigned long avail;\r
+ unsigned long next_off;\r
+ xms_node_t *next;\r
+ }\r
+xms_head_t;\r
+\r
+#define XMSBLOCK 16384u\r
+#define XMSBLOCKSHIFT 14\r
+\r
+extern void LSHL( unsigned long far *SHLnumber, unsigned short n );\r
+\r
+extern unsigned short XMS_available( void );\r
+\r
+extern unsigned short XMSblk_available( void );\r
+\r
+extern short XMS_alloc(unsigned short rsrvd,\r
+ unsigned short far *size\r
+ );\r
+extern short XMS_dealloc(unsigned short Hdl );\r
+extern short XMStoMem(unsigned short Handle, // XMS handle returned by XMS_alloc()\r
+ unsigned short blk, // which 16k block to copy to\r
+ unsigned short blkAdr, // offset within 16k block\r
+ unsigned short Bytes, // bytes to copy\r
+ void far *memAdr\r
+ );\r
+extern short MemToXMS(unsigned short Handle,\r
+ unsigned short blk,\r
+ unsigned short blkAdr,\r
+ unsigned short Bytes,\r
+ void far *memAdr\r
+ );\r
+\r
+// call these for ease\r
+short alloc_xms(unsigned short far *size); // size in 16k blocks\r
+// NOTE size is changed to the amount block size was altered by!\r
+// normaly this is zero\r
+\r
+short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n);\r
+short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n);\r
+void deinit_xms(void);\r
+short init_xms(unsigned short min_blocks);\r
+void qfree_xms(xms_node_t *node);\r
+xms_node_t *qalloc_xms(unsigned long size);\r
+xms_node_t *xms_open(char *file);\r
+short xms_read(void far *buffer, unsigned short n, xms_node_t *node);\r
+short xms_write(void far *buffer, unsigned short n, xms_node_t *node);\r
+long xms_tell(xms_node_t *node);\r
+short xms_seek(xms_node_t *node, long off, short whence);\r
+void xms_close(xms_node_t *node);\r
+\r
+extern xms_head_t xms_head;\r
+\r
+#endif\r
+/* ---------------------------------- end of file --------------------- */\r
+\r
+XMEM.H ------------- END --------------------------------------------------\r
+\r
+xmem.asm --------------------- START --------------------------------------\r
+;-----------------------------------------------------------------------\r
+;\r
+.MODEL MEDIUM\r
+\r
+ EXTmemError EQU 7\r
+ XMSmemError EQU 8\r
+\r
+\r
+ ShortAdr EQU 0\r
+ LongAdr EQU 1\r
+\r
+procname MACRO Pnam\r
+ PUBLIC _&Pnam&\r
+_&Pnam& PROC FAR\r
+ENDM\r
+\r
+endproc MACRO Pnam\r
+\r
+_&Pnam& ENDP\r
+\r
+ENDM\r
+\r
+pwrlolvl_TEXT SEGMENT WORD PUBLIC 'CODE'\r
+\r
+ ASSUME CS:pwrlolvl_TEXT, DS:pwrlolvl_TEXT, ES:pwrlolvl_TEXT\r
+\r
+SUBTTL (Local Procedure) XMS_setup - find a XMS driver.\r
+PAGE+\r
+\r
+ EVEN\r
+XMSwordByte LABEL BYTE\r
+XMSword DW 0\r
+\r
+XMSmoveSTRUC STRUC\r
+\r
+Length DW 0\r
+LengthX DW 0\r
+SrcHandle DW 0\r
+SrcOffset DW 0\r
+SrcOffsetX DW 0\r
+DestHandle DW 0\r
+DestOffset DW 0\r
+DestOffsetX DW 0\r
+\r
+XMSmoveSTRUC ENDS\r
+\r
+XMSmainGET XMSmoveSTRUC <>\r
+XMSmainPUT XMSmoveSTRUC <>\r
+XMSwordGET XMSmoveSTRUC <2,,,,,,OFFSET XMSword>\r
+XMSwordPUT XMSmoveSTRUC <2,,,OFFSET XMSword>\r
+\r
+XMSfunctAdr DW 0, 0\r
+\r
+; Don't try to call this from your programs\r
+\r
+XMS_setup PROC NEAR\r
+\r
+ PUSH DS\r
+ PUSH ES\r
+ PUSH BX\r
+\r
+ MOV AX,CS ; Set Data segment to the code segment.\r
+ MOV DS,AX ;\r
+ MOV [XMSwordGET.DestOffsetX],AX ; Set up the move data structures.\r
+ MOV [XMSwordPUT.SrcOffsetX],AX ;\r
+\r
+ MOV AX,4300H ; See if a XMS Driver Exists.\r
+ INT 2FH ;\r
+ CMP AL,80H ;\r
+ MOV AX,0 ;\r
+ JNE XMS_setup01 ; Return 0 if not.\r
+\r
+ MOV AX,4310H ; If so, set the driver's function\r
+ INT 2FH ; address.\r
+ MOV [XMSfunctAdr],BX ;\r
+ MOV [XMSfunctAdr+2],ES ;\r
+\r
+ MOV AX,1 ; Return 1.\r
+\r
+ XMS_setup01:\r
+ POP BX\r
+ POP ES\r
+ POP DS\r
+\r
+ RET\r
+\r
+XMS_setup ENDP\r
+\r
+SUBTTL LSHL - Shift an unsigned long left\r
+PAGE+\r
+\r
+ ;****************************************************************************\r
+ ;* \r
+ ;* Shift an unsigned long integer left n number of bits.\r
+ ;*\r
+ ;****************************************************************************\r
+\r
+ ;\r
+ ; Stack frame definition for void LSHL( unsigned long *SHLnumber, unsigned n );\r
+ ;\r
+\r
+LSHLparms STRUC\r
+\r
+ DW 0, 0\r
+ DW 0\r
+SHLadr DD ?\r
+SHLn DW ?\r
+\r
+LSHLparms ENDS\r
+\r
+procname LSHL\r
+\r
+ PUSH BP\r
+ MOV BP,SP\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+\r
+ PUSH DS\r
+ LDS BX,SHLadr[BP]\r
+ MOV CX,SHLn[BP]\r
+\r
+ MOV AX,[BX] ; Get the long integer.\r
+ MOV DX,[BX+2] ; \r
+\r
+ LSHL_01:\r
+ SHL AX,1 ; Do the long shift.\r
+ RCL DX,1 ; \r
+ LOOP LSHL_01 ; \r
+\r
+ MOV [BX],AX ; Replace the addressed number.\r
+ MOV [BX+2],DX ; \r
+\r
+ POP DS\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ POP BP\r
+ RET ; Exit\r
+\r
+endproc LSHL\r
+\r
+\r
+SUBTTL Extended Memory - Stack template for EXTget, EXTput\r
+PAGE+\r
+\r
+EXTgpparms STRUC\r
+\r
+ DW 0, 0\r
+ DW 0\r
+extgpBase DW ?\r
+extgpblk DW ?\r
+extgpblkAdr DW ?\r
+extgpBytes DW ?\r
+extgpmemAdr DW ?\r
+ DW ?\r
+\r
+EXTgpparms ENDS\r
+\r
+\r
+\r
+SUBTTL Extended Memory - XMS - Return total XMS memory.\r
+PAGE+\r
+\r
+ ; Use this function to detect wether or not XMS driver installed\r
+ ;\r
+ ; Stack frame definition for unsigned XMS_available( void );\r
+ ;\r
+ ; The total XMS memory available (in 16k blocks) is returned.\r
+ ;\r
+procname XMS_available\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+\r
+ CALL XMS_setup ; Ensure XMS memory is set.\r
+ TEST AX,AX ;\r
+ JZ XMS_available01 ; Return zero if not.\r
+\r
+ MOV AH,08H ; Set the size function code.\r
+ CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size.\r
+ TEST AX,AX ;\r
+ JZ XMS_available01 ;\r
+\r
+ MOV AX,DX ; Set available Kbytes.\r
+ SUB AX,64 ; Subtract out the HMA (HIMEM.SYS bug).\r
+ JNC XMS_available01 ;\r
+ XOR AX,AX ; Set zero if underflow.\r
+\r
+ XMS_available01:\r
+ MOV CL,4 ; Divide Kbytes by 16 for blocks.\r
+ SHR AX,CL ;\r
+\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ RET ; Exit\r
+\r
+endproc XMS_available\r
+\r
+SUBTTL Extended Memory - XMS - Return largest block XMS mem.\r
+PAGE+\r
+\r
+ ;\r
+ ; Stack frame definition for unsigned XMSblk_available( void );\r
+ ;\r
+ ; The size of the largest block of XMS memory available,\r
+ ; (in 16Kbyte blocks) is returned.\r
+ ;\r
+procname XMSblk_available\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+\r
+ CALL XMS_setup ; Ensure XMS memory is set.\r
+ TEST AX,AX ;\r
+ JZ XMSblk_available01 ; Return zero if not.\r
+\r
+ MOV AH,08H ; Set the size function code.\r
+ CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size.\r
+ TEST AX,AX ;\r
+ JZ XMSblk_available01 ;\r
+\r
+ SUB DX,64 ; Subtract out the HMA (HIMEM.SYS bug).\r
+ JNC XMSblk_available0X ;\r
+ XOR DX,DX ; Set zero if underflow.\r
+\r
+ XMSblk_available0X:\r
+ CMP AX,DX ;\r
+ JBE XMSblk_available01 ;\r
+ MOV AX,DX ; Set available Kbytes.\r
+\r
+ XMSblk_available01:\r
+ MOV CL,4 ; Divide Kbytes by 16 for blocks.\r
+ SHR AX,CL ;\r
+\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ RET ; Exit\r
+\r
+endproc XMSblk_available\r
+\r
+SUBTTL Extended Memory - XMS De-allocate a memory block.\r
+PAGE+\r
+\r
+ ;\r
+ ; Stack frame definition for int XMS_dealloc( int Hdl );\r
+ ;\r
+ ; Zero is returned if the operation fails, non-zero if success.\r
+ ;\r
+ ; its really important to do this, only other way to recover\r
+ ; XMS blocks is to re-boot\r
+\r
+XMSdealparms STRUC\r
+\r
+ DW 0, 0\r
+ DW 0\r
+xmsdealHdl DW ?\r
+\r
+XMSdealparms ENDS\r
+\r
+\r
+procname XMS_dealloc\r
+\r
+ PUSH BP\r
+ MOV BP,SP\r
+\r
+ PUSH BX\r
+ PUSH DX\r
+\r
+; CALL XMS_setup ; Ensure XMS memory is set.\r
+; TEST AX,AX ;\r
+; JZ XMS_dealloc01 ; Return zero if not.\r
+\r
+ MOV DX,xmsdealHdl[BP] ; Get the handle to de-allocate.\r
+ MOV AH,0AH ;\r
+\r
+ CALL DWORD PTR CS:[XMSfunctAdr] ; De-allocate it.\r
+\r
+ XMS_dealloc01:\r
+ POP DX\r
+ POP BX\r
+\r
+ POP BP\r
+ RET ; Exit\r
+\r
+endproc XMS_dealloc\r
+\r
+SUBTTL Extended Memory - XMS Allocate a memory block.\r
+PAGE+\r
+\r
+ ;\r
+ ; Stack frame definition for int XMS_alloc( unsigned rsrvd, *size );\r
+ ;\r
+ ; rsrved and size are in 16K byte blocks.\r
+ ; rsrved is mem set aside for EMS, generaly zero\r
+ ;\r
+ ; Zero is returned if the operation fails.\r
+ ; Block (XMS) handle is returned if success.\r
+ ;\r
+ ; size - is reduced by the amount of XMS memory actually allocated.\r
+ ;\r
+\r
+XMSalparms STRUC\r
+\r
+ DW 0, 0\r
+ DW 0\r
+xmsalrsrvd DW ?\r
+xmsalsize DD ?\r
+\r
+XMSalparms ENDS\r
+\r
+procname XMS_alloc\r
+\r
+ PUSH BP\r
+ MOV BP,SP\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH DI\r
+ PUSH ES\r
+ PUSH DS\r
+\r
+ MOV AX,CS ; Set the data segment to the code\r
+ MOV DS,AX ; segment.\r
+\r
+ MOV CX,4 ;\r
+ ADD xmsalrsrvd[BP],CX ; Subtract out the HMA (HIMEM.SYS bug).\r
+ SHL xmsalrsrvd[BP],CL ; Convert reserved blocks to K-bytes.\r
+\r
+ LES DI,xmsalsize[BP] ; Load size address.\r
+ XOR AX,AX ;\r
+ MOV BX,ES:[DI] ; Get the requested size in blocks.\r
+\r
+ TEST BX,0F000H ; Check for more than 64 Megabytes.\r
+ JZ XMS_alloc01 ;\r
+ MOV BX,00FFFH ;\r
+\r
+ XMS_alloc01:\r
+ MOV CL,4 ;\r
+ SHL BX,CL ; Convert to K-Bytes.\r
+ MOV CX,BX ; In CX.\r
+ JZ XMS_alloc05 ; Return zero if no size requested.\r
+\r
+; CALL XMS_setup ; Ensure XMS memory is set.\r
+; TEST AX,AX ;\r
+; JZ XMS_alloc05 ; Return zero if not.\r
+\r
+ XOR BX,BX ;\r
+ MOV AH,08H ; Set to Query Free XMS Memory.\r
+ CALL DWORD PTR [XMSfunctAdr] ;\r
+\r
+ SUB DX,xmsalrsrvd[BP] ; Subtract out reserved blocks.\r
+ JB XMS_alloc03 ; Ensure no borrow.\r
+ CMP AX,DX ;\r
+ JBE XMS_alloc02 ;\r
+ MOV AX,DX ;\r
+\r
+ XMS_alloc02:\r
+ MOV DX,AX ;\r
+ CMP AX,68 ; Ensure enough memory to allocate.\r
+\r
+ XMS_alloc03:\r
+ MOV AX,0 ;\r
+ JB XMS_alloc05 ; Exit if not.\r
+\r
+ CMP BL,80H ; Check for errors.\r
+ JE XMS_alloc05 ;\r
+ CMP BL,81H ;\r
+ JE XMS_alloc05 ;\r
+\r
+ CMP CX,DX ; Check actual against requested size.\r
+ JBE XMS_alloc04 ;\r
+ MOV CX,DX ; Set if actual < requested.\r
+\r
+ XMS_alloc04:\r
+ MOV DX,CX ; Set requested size.\r
+ MOV AH,09H ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Allocate it.\r
+ DEC AX ; Check for errors.\r
+ MOV AX,0 ;\r
+ JNZ XMS_alloc05 ;\r
+\r
+\r
+ MOV AX,CX ; Convert allocated size in KBytes\r
+ MOV CL,4 ; to allocated blocks.\r
+ SHR AX,CL ;\r
+\r
+ SUB ES:[DI],AX ; Subtract the blocks allocated.\r
+ MOV AX,DX ; Set to return the handle.\r
+\r
+ XMS_alloc05:\r
+ POP DS\r
+ POP ES\r
+ POP DI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ POP BP\r
+ RET ; Exit\r
+\r
+endproc XMS_alloc\r
+\r
+SUBTTL Extended Memory - XMS get, put Stack Frame definition\r
+PAGE+\r
+\r
+\r
+XMSgpparms STRUC\r
+\r
+ DW 0, 0\r
+ DW 0\r
+xmsgpHdl DW ?\r
+xmsgpblk DW ?\r
+xmsgpblkAdr DW ?\r
+xmsgpBytes DW ?\r
+xmsgpmemAdr DD ?\r
+\r
+XMSgpparms ENDS\r
+\r
+SUBTTL Extended Memory - XMStoMem\r
+PAGE+\r
+\r
+\r
+ ;\r
+ ; Stack frame definition for int XMStoMem( unsigned Handle,\r
+ ; unsigned blk,\r
+ ; unsigned blkAdr,\r
+ ; unsigned Bytes,\r
+ ; char *memAdr\r
+ ; );\r
+ ;\r
+ ; XMSmemError is returned if the operation fails, Zero if success.\r
+ ;\r
+\r
+procname XMStoMem\r
+\r
+ PUSH BP\r
+ MOV BP,SP\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH ES\r
+ PUSH DS\r
+\r
+ MOV AX,CS ; Set Data Segment to Code Segment.\r
+ MOV DS,AX ;\r
+\r
+ MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer.\r
+ LES BX,xmsgpmemAdr[BP] ; Get the memory address.\r
+ MOV DX,xmsgpHdl[BP] ; Get the XMS handle.\r
+ MOV [XMSmainGET.SrcHandle],DX ; Set it in the move structures.\r
+ MOV [XMSwordGET.SrcHandle],DX ;\r
+\r
+ XOR DX,DX ;\r
+ MOV DI,xmsgpblk[BP] ; Get the block number.\r
+ SHR DI,1 ; Form the 32 bit XMS address in\r
+ RCR DX,1 ; DI:DX.\r
+ SHR DI,1 ;\r
+ RCR DX,1 ;\r
+ ADD DX,xmsgpblkAdr[BP] ;\r
+\r
+ TEST CX,1 ; Check for an odd number of bytes\r
+ JZ XMStoMem02 ; to transfer.\r
+\r
+ DEC CX ; Decrement to an even number of bytes.\r
+\r
+ TEST DX,1 ; Check for an odd XMS address.\r
+ JZ XMStoMem01 ;\r
+\r
+ ; XMS address is odd.\r
+ ; -------------------\r
+ DEC DX ;\r
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.\r
+ MOV [XMSwordGET.SrcOffsetX],DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ XMStoMem03 ; Error out if error.\r
+\r
+ MOV AX,[XMSword] ; Get the moved word.\r
+\r
+ MOV ES:[BX],AH ; Move the odd byte to memory.\r
+\r
+ INC BX ; Reset the memory address.\r
+ ADD DX,2 ; And the XMS address.\r
+\r
+ JMP XMStoMem02 ; Move the block.\r
+\r
+\r
+ XMStoMem01:\r
+ ; XMS address is even.\r
+ ; --------------------\r
+ ADD DX,CX ;\r
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.\r
+ SUB DX,CX ;\r
+ MOV [XMSwordGET.SrcOffsetX],DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ XMStoMem03 ; Error out if error.\r
+\r
+ MOV AX,[XMSword] ; Get the moved word.\r
+\r
+ XCHG DI,CX ;\r
+ MOV ES:[BX+DI],AL ; Move the odd byte to memory.\r
+ XCHG DI,CX ;\r
+\r
+ XMStoMem02:\r
+ JCXZ XMStoMem04 ; Avoid a zero byte move.\r
+\r
+ MOV XMSmainGET.Length,CX ; Set length for the move.\r
+\r
+ MOV XMSmainGET.DestOffset,BX ; Set Memory address.\r
+ MOV XMSmainGET.DestOffsetX,ES ;\r
+\r
+ MOV XMSmainGET.SrcOffset,DX ; Set XMS address.\r
+ MOV XMSmainGET.SrcOffsetX,DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSmainGET ; Set address of the move structure.\r
+\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ DEC AX ; Check for errors.\r
+ JZ XMStoMem05\r
+\r
+ XMStoMem03:\r
+ MOV AX,XMSmemError ; Set error code if error.\r
+ JMP XMStoMem05 ;\r
+\r
+ XMStoMem04:\r
+ XOR AX,AX ;\r
+\r
+ XMStoMem05:\r
+ POP DS\r
+ POP ES\r
+ POP DI\r
+ POP SI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ POP BP\r
+ RET ; Exit\r
+\r
+endproc XMStoMem\r
+\r
+SUBTTL Extended Memory - MemToXMS\r
+PAGE+\r
+\r
+\r
+ ;\r
+ ; Stack frame definition for int MemToXMS( unsigned Handle,\r
+ ; unsigned blk,\r
+ ; unsigned blkAdr,\r
+ ; unsigned Bytes,\r
+ ; char *memAdr\r
+ ; );\r
+ ;\r
+ ; XMSmemError is returned if the operation fails, Zero if success.\r
+ ;\r
+\r
+procname MemToXMS\r
+\r
+ PUSH BP\r
+ MOV BP,SP\r
+\r
+ PUSH BX\r
+ PUSH CX\r
+ PUSH DX\r
+ PUSH SI\r
+ PUSH DI\r
+ PUSH ES\r
+ PUSH DS\r
+\r
+ MOV AX,CS ;\r
+ MOV DS,AX ;\r
+\r
+ MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer.\r
+ LES BX,xmsgpmemAdr[BP] ; Get the memory address.\r
+ MOV DX,xmsgpHdl[BP] ; Get the XMS handle.\r
+ MOV [XMSmainPUT.DestHandle],DX ; Set it in the move structures.\r
+ MOV [XMSwordPUT.DestHandle],DX ;\r
+ MOV [XMSwordGET.SrcHandle],DX ;\r
+\r
+ XOR DX,DX ;\r
+ MOV DI,xmsgpblk[BP] ; Get the block number.\r
+ SHR DI,1 ; Form the 32 bit XMS address in\r
+ RCR DX,1 ; DI:DX.\r
+ SHR DI,1 ;\r
+ RCR DX,1 ;\r
+ ADD DX,xmsgpblkAdr[BP] ;\r
+\r
+ TEST CX,1 ; Check for an odd number of bytes\r
+ JZ MemToXMS02 ; to transfer.\r
+\r
+ DEC CX ; Decrement to an even number of bytes.\r
+\r
+ TEST DX,1 ; Check for an odd XMS address.\r
+ JZ MemToXMS01 ;\r
+\r
+ ; XMS address is odd.\r
+ ; -------------------\r
+ DEC DX ;\r
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.\r
+ MOV [XMSwordGET.SrcOffsetX],DI ;\r
+ MOV [XMSwordPUT.DestOffset],DX ;\r
+ MOV [XMSwordPUT.DestOffsetX],DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ MemToXMS03 ; Error out if error.\r
+\r
+ MOV AH,ES:[BX] ; Get the odd memory byte.\r
+\r
+ MOV [XMSwordByte+1],AH ; Put it in the moved word.\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordPUT ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ MemToXMS03 ; Error out if error.\r
+\r
+ INC BX ; Reset the memory address.\r
+ ADD DX,2 ; And the XMS address.\r
+\r
+ JMP MemToXMS02 ; Move the block.\r
+\r
+ MemToXMS01:\r
+ ; XMS address is even.\r
+ ; --------------------\r
+ ADD DX,CX ;\r
+ MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address.\r
+ MOV [XMSwordPUT.DestOffset],DX ;\r
+ SUB DX,CX ;\r
+ MOV [XMSwordGET.SrcOffsetX],DI ;\r
+ MOV [XMSwordPUT.DestOffsetX],DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordGET ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ MemToXMS03 ; Error out if error.\r
+\r
+ XCHG DI,CX ;\r
+ MOV AL,ES:[BX+DI] ; Get the odd memory byte.\r
+ XCHG DI,CX ;\r
+\r
+ MOV [XMSwordByte],AL ; Set the moved word.\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSwordPUT ; Set address of the move structure.\r
+\r
+ PUSH BX ;\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ POP BX ;\r
+ DEC AX ; Check for errors.\r
+ JNZ MemToXMS03 ; Error out if error.\r
+\r
+ MemToXMS02:\r
+ JCXZ MemToXMS04 ; Avoid a zero byte move.\r
+\r
+ MOV XMSmainPUT.Length,CX ; Set length for the move.\r
+\r
+ MOV XMSmainPUT.SrcOffset,BX ; Set Memory address.\r
+ MOV XMSmainPUT.SrcOffsetX,ES ;\r
+\r
+ MOV XMSmainPUT.DestOffset,DX ; Set XMS address.\r
+ MOV XMSmainPUT.DestOffsetX,DI ;\r
+\r
+ MOV AH,0BH ; Set the XMS move, function code.\r
+ MOV SI,OFFSET XMSmainPUT ; Set address of the move structure.\r
+\r
+ CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
+ DEC AX ; Check for errors.\r
+ JZ MemToXMS05\r
+\r
+ MemToXMS03:\r
+ MOV AX,XMSmemError ; Set error code if error.\r
+ JMP MemToXMS05 ;\r
+\r
+ MemToXMS04:\r
+ XOR AX,AX ;\r
+\r
+ MemToXMS05:\r
+ POP DS\r
+ POP ES\r
+ POP DI\r
+ POP SI\r
+ POP DX\r
+ POP CX\r
+ POP BX\r
+\r
+ POP BP\r
+ RET ; Exit\r
+\r
+endproc MemToXMS\r
+\r
+\r
+SUBTTL Last Page\r
+PAGE+\r
+\r
+pwrlolvl_TEXT ENDS\r
+\r
+ END\r
+\r
+\r
+xmem.asm --------------------- END --------------------------------------\r
+\r
+xmemc.c ---------------------------- START -------------------------\r
+\r
+/*\r
+\r
+ Copyright 1994 Alec Russell, ALL rights reserved\r
+ Permission granted to use as you wish.\r
+\r
+ Slightly higher level xms calls than xmem.asm\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <io.h>\r
+#include <string.h>\r
+#include <malloc.h>\r
+\r
+#include <xmem.h>\r
+\r
+xms_head_t xms_head={0}; // set handle to zero\r
+\r
+\r
+/* ---------------------- alloc_xms() ----------------- February 19,1994 */\r
+short alloc_xms(unsigned short far *size) // size in 16k blocks\r
+{\r
+ return(XMS_alloc(0, size));\r
+}\r
+\r
+/* ---------------------- xms_to_mem() ---------------- February 19,1994 */\r
+short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n)\r
+{\r
+ unsigned short block, boff;\r
+\r
+ block=off >> XMSBLOCKSHIFT;\r
+ boff=off - (block << XMSBLOCKSHIFT);\r
+\r
+ return(XMStoMem(handle, block, boff, n, p));\r
+}\r
+\r
+/* ---------------------- mem_to_xms() ---------------- February 19,1994 */\r
+short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n)\r
+{\r
+ unsigned short block, boff;\r
+\r
+ block=off >> XMSBLOCKSHIFT;\r
+ boff=off - (block << XMSBLOCKSHIFT);\r
+\r
+ return(MemToXMS(handle, block, boff, n, p));\r
+}\r
+\r
+/* ---------------------- qalloc_xms() -------------------- March 8,1994 */\r
+xms_node_t *qalloc_xms(unsigned long size)\r
+{\r
+ xms_node_t *node=NULL;\r
+ xms_node_t *t1;\r
+\r
+ if ( size <= xms_head.avail )\r
+ {\r
+ // look for existing node\r
+ t1=xms_head.next;\r
+ while ( t1 )\r
+ {\r
+ if ( t1->used == 0 && t1->size >= size )\r
+ {\r
+ t1->off=0;\r
+ t1->used=1;\r
+ node=t1;\r
+ break;\r
+ }\r
+ else\r
+ t1=t1->next;\r
+ }\r
+\r
+ if ( node == NULL ) // didn't find existing node\r
+ {\r
+ node=malloc(sizeof(xms_node_t));\r
+ if ( node )\r
+ {\r
+ node->off=0;\r
+ node->used=1;\r
+ node->size=size;\r
+ node->next=NULL;\r
+ node->start=xms_head.next_off;\r
+ xms_head.avail-=size;\r
+ xms_head.next_off+=size;\r
+ if ( xms_head.next == NULL )\r
+ {\r
+ xms_head.next=node;\r
+ }\r
+ else\r
+ {\r
+ t1=xms_head.next;\r
+ while ( t1->next )\r
+ t1=t1->next;\r
+ t1->next=node;\r
+ }\r
+ }\r
+ else\r
+ pr2("out of near mem in qalloc_xms");\r
+ }\r
+ }\r
+ else\r
+ pr2("out of xms mem in qalloc size %lu avail %lu", size, xms_head.avail);\r
+\r
+ return(node);\r
+}\r
+\r
+/* ---------------------- qfree_xms() --------------------- March 8,1994 */\r
+void qfree_xms(xms_node_t *node)\r
+{\r
+ xms_node_t *t1;\r
+\r
+ if ( xms_head.next )\r
+ {\r
+ t1=xms_head.next;\r
+ while ( t1 != node && t1 )\r
+ t1=t1->next;\r
+\r
+ if ( t1 )\r
+ {\r
+ t1->used=0;\r
+ }\r
+ else\r
+ pr2("ERROR didn't find node qfree");\r
+ }\r
+ else\r
+ {\r
+ pr2("ATTEMPTED to qfree empty list");\r
+ }\r
+}\r
+\r
+/* ---------------------- xms_open() ---------------------- March 8,1994 */\r
+xms_node_t *xms_open(char *file)\r
+{\r
+ int i;\r
+ xms_node_t *node=NULL;\r
+ FILE *fp;\r
+ char *buffer;\r
+ unsigned long off;\r
+\r
+ fp=fopen(file, "rb");\r
+ if ( fp )\r
+ {\r
+ node=qalloc_xms(filelength(fileno(fp)));\r
+ if ( node )\r
+ {\r
+ buffer=malloc(4096);\r
+ if ( buffer )\r
+ {\r
+ off=0l;\r
+ while ( (i=fread(buffer, 1, 4096, fp)) )\r
+ {\r
+ mem_to_xms(xms_head.handle, (char far *)buffer, off+node->start, i);\r
+ off+=i;\r
+ }\r
+\r
+ free(buffer);\r
+ }\r
+ else\r
+ pr2("out of mem in xms_open 1");\r
+ }\r
+\r
+ fclose(fp);\r
+ }\r
+ else\r
+ pr2("ERROR opening %s in xms_open", file);\r
+\r
+ return(node);\r
+}\r
+\r
+/* ---------------------- xms_read() ---------------------- March 8,1994 */\r
+short xms_read(void far *buffer, unsigned short n, xms_node_t *node)\r
+{\r
+\r
+ if ( node->off >= node->size )\r
+ return 0;\r
+\r
+ if ( n+node->off > node->size )\r
+ n=node->size - node->off;\r
+\r
+ xms_to_mem(xms_head.handle, buffer, node->start+node->off, n);\r
+ node->off+=n;\r
+\r
+ return(n);\r
+}\r
+\r
+/* ---------------------- xms_write() ---------------------- March 8,1994 */\r
+short xms_write(void far *buffer, unsigned short n, xms_node_t *node)\r
+{\r
+\r
+ if ( node->off >= node->size )\r
+ return 0;\r
+\r
+ if ( n+node->off > node->size )\r
+ n=node->size - node->off;\r
+\r
+ mem_to_xms(xms_head.handle, buffer, node->start+node->off, n);\r
+ node->off+=n;\r
+\r
+ return(n);\r
+}\r
+\r
+\r
+/* ---------------------- xms_tell() ---------------------- March 8,1994 */\r
+long xms_tell(xms_node_t *node)\r
+{\r
+ return node->off;\r
+}\r
+\r
+/* ---------------------- xms_seek() ---------------------- March 8,1994 */\r
+short xms_seek(xms_node_t *node, long off, short whence)\r
+{\r
+ short err=0;\r
+\r
+ switch ( whence )\r
+ {\r
+ case SEEK_SET:\r
+ if ( off < 0l || off > node->size )\r
+ err=1;\r
+ else\r
+ node->off=off;\r
+ break;\r
+\r
+ case SEEK_END:\r
+ if ( off > 0l || (node->size + off) < 0l )\r
+ err=1;\r
+ else\r
+ node->off=node->size + off;\r
+ break;\r
+\r
+ case SEEK_CUR:\r
+ if ( node->off + off < 0l || node->off + off > node->size )\r
+ err=1;\r
+ else\r
+ node->off+=off;\r
+ break;\r
+ }\r
+\r
+ return(err);\r
+}\r
+\r
+/* ---------------------- xms_close() --------------------- March 8,1994 */\r
+void xms_close(xms_node_t *node)\r
+{\r
+ qfree_xms(node);\r
+}\r
+\r
+/* ---------------------- init_xms() ---------------------- March 8,1994 */\r
+short init_xms(unsigned short min_blocks)\r
+{\r
+ unsigned short blocks;\r
+\r
+ blocks=XMSblk_available();\r
+ if ( blocks >= min_blocks )\r
+ {\r
+ memset(&xms_head, 0, sizeof(xms_head_t));\r
+ if ( (xms_head.handle=alloc_xms(&blocks)) )\r
+ {\r
+ pr2("blocks minus by = %u", blocks);\r
+ min_blocks-=blocks;\r
+ xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK;\r
+ blocks=min_blocks;\r
+ }\r
+ else\r
+ blocks=0;\r
+ }\r
+ else\r
+ blocks=0;\r
+\r
+ return(blocks);\r
+}\r
+\r
+/* ---------------------- deinit_xms() -------------------- March 8,1994 */\r
+void deinit_xms(void)\r
+{\r
+ xms_node_t *t1, *t2;\r
+\r
+ if ( xms_head.handle )\r
+ {\r
+ XMS_dealloc(xms_head.handle);\r
+ if ( xms_head.next )\r
+ {\r
+ t1=xms_head.next;\r
+ t2=t1->next;\r
+ while ( t1 )\r
+ {\r
+ free(t1);\r
+ t1=t2;\r
+ t2=t1->next;\r
+ }\r
+ }\r
+\r
+ memset(&xms_head, 0, sizeof(xms_head_t));\r
+ }\r
+}\r
+/* --------------------------- end of file ------------------------- */\r
+\r
+/*\r
+\r
+Not sure how to use this?\r
+\r
+call init_xms(x) to allocate a big chunk of xms.\r
+x is in 'blocks' of 16Kb. Pick X big enough to buffer all the files\r
+you want to place in xms.\r
+\r
+call xms_open("filename); for each file to be buffered. This copies the file\r
+int xms.\r
+\r
+then use xms_read(), xms_write(), and xms_seek() to read the file from\r
+xms instead of disk.\r
+\r
+call deinit_xms() just before exit to clean up.\r
+\r
+You can also use the lower level calls directly.\r
+\r
+*/\r
+xmemc.c ---------------------------- END -------------------------\r
#include <stdlib.h>\r
#include <mem.h>\r
\r
-#include "memory.c"\r
+#include "memory.h"\r
\r
void TransformData(char *pEmmData, unsigned int len)\r
{\r
\r
#include "memory.h"\r
\r
-// static globals --------------------------------\r
+ //static globals --------------------------------\r
\r
static int ActiveEMList[MAXEMHANDLES];\r
static unsigned int EMMSeg;\r
\r
-// forward declarations ---------------------------------\r
+ //forward declarations ---------------------------------\r
\r
static int EMPresent(void);\r
static int EMReady(void);\r
mov ah,0x42 /* get EMM free page count */\r
int 0x67\r
or ah,ah\r
- //js InternalError /* returns 80, 81, or 84 hex on error */\r
+ js InternalError /* returns 80, 81, or 84 hex on error */\r
mov Pages,bx /* number of unallocated 16K pages */\r
}\r
RtnVal = ((unsigned long)Pages << 14); /* Pages * 16K rtns bytes*/\r
\r
-//InternalError:\r
-\r
+InternalError:\r
return(RtnVal);\r
} /* End of EMMCoreLeft() */\r
\r
mov dx,Handle\r
int 0x67\r
or ah,ah\r
- //js NoGo /* returns 80 to 88 hex on error */\r
+ js NoGo /* returns 80 to 88 hex on error */\r
}\r
RtnCode = TRUE;\r
\r
-//NoGo:\r
+NoGo:\r
\r
return(RtnCode);\r
} /* End of EMMRealloc() */\r
mov ah,0x40 /* get EM Manager Status */\r
int 0x67\r
or ah,ah\r
- //jns Ready /* returns 80, 81, or 84 hex on error */\r
+ jns Ready /* returns 80, 81, or 84 hex on error */\r
}\r
return(FALSE);\r
\r
-//Ready:\r
+Ready:\r
return(TRUE);\r
} /* End of EMReady() */\r
\r
mov ah,0x41 /* get EMM page frame segment */\r
int 0x67\r
or ah,ah\r
- //js NotReady /* returns 80, 81, or 84 hex on error */\r
+ js NotReady /* returns 80, 81, or 84 hex on error */\r
mov EMSegment,bx\r
}\r
return(EMSegment); /*lint !e530 */\r
\r
-//NotReady:\r
+NotReady:\r
return(NOTREADY);\r
} /* End of GetEMMSeg() */\r
\r
mov bx,NumPages /* number of 16K pages to allocate */\r
int 0x67\r
or ah,ah /* returns 80 to 89 hex on error */\r
- //js NoHandle\r
+ js NoHandle\r
mov NewHandle,dx /* retrieve handle */\r
}\r
return(NewHandle);\r
\r
-//NoHandle:\r
+NoHandle:\r
return(NO_DATA);\r
} /* End of GetEMHandle() */\r
\r
mov dx,Handle\r
int 0x67\r
or ah,ah /* returns 80 to 8B hex on error */\r
- //js NoMapping\r
+ js NoMapping\r
}\r
RtnCode = SUCCESS;\r
\r
-//NoMapping:\r
+NoMapping:\r
return(RtnCode);\r
} /* End of EMMap() */\r
\r
mov dx,Handle\r
int 0x67\r
or ah,ah /* returns 80 to 86 hex on error */\r
- //js NotFreed\r
+ js NotFreed\r
}\r
return(SUCCESS);\r
\r
-//NotFreed: /* must retry if unsuccessful */\r
+NotFreed: /* must retry if unsuccessful */\r
return(NO_DATA);\r
} /* End of FreeEMHandle() */\r
\r
mov dx,Handle\r
int 0x67\r
or ah,ah /* returns 80 to 84 hex on error */\r
- //js BadHandle\r
+ js BadHandle\r
mov NumPages,bx\r
}\r
-//BadHandle:\r
+BadHandle:\r
\r
return(NumPages);\r
} /* End of GetNumPages() */\r
mov dx,Handle\r
int 0x67\r
or ah,ah\r
- //js Unsaved /* out of save space error */\r
+ js Unsaved /* out of save space error */\r
}\r
RtnCode = SUCCESS;\r
\r
-//Unsaved:\r
+Unsaved:\r
return(RtnCode);\r
} /* End of EMStateSave() */\r
\r
-"wcp -mh emm.c" at\r
+wcp -mh emm.c\r
-
/*
-
- Copyright 1994 Alec Russell, ALL rights reserved
- Permission granted to use as you wish.
-
+ Written by Alexander J. Russell 1994
+
+ Placed in the public Domain by Alec Russell, March 1995
+
Slightly higher level xms calls than xmem.asm
-
+
*/
-
+
#include <stdio.h>
#include <io.h>
#include <string.h>
#include <malloc.h>
-
-#include <xmem.h>
-
+
+#include "src\lib\exmm\xmem.h"
+
xms_head_t xms_head={0}; // set handle to zero
-
-
+
+
/* ---------------------- alloc_xms() ----------------- February 19,1994 */
short alloc_xms(unsigned short far *size) // size in 16k blocks
{
return(XMS_alloc(0, size));
}
-
+
+
+
/* ---------------------- xms_to_mem() ---------------- February 19,1994 */
-short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n)
+short xms_to_mem(unsigned short handle, void far *p, unsigned long off,
+unsigned short n)
{
unsigned short block, boff;
-
+
block=off >> XMSBLOCKSHIFT;
boff=off - (block << XMSBLOCKSHIFT);
-
+
return(XMStoMem(handle, block, boff, n, p));
}
-
+
+
/* ---------------------- mem_to_xms() ---------------- February 19,1994 */
-short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n)
+short mem_to_xms(unsigned short handle, void far *p, unsigned long off,
+unsigned short n)
{
unsigned short block, boff;
-
+
block=off >> XMSBLOCKSHIFT;
boff=off - (block << XMSBLOCKSHIFT);
-
+
return(MemToXMS(handle, block, boff, n, p));
}
-
+
+
/* ---------------------- qalloc_xms() -------------------- March 8,1994 */
xms_node_t *qalloc_xms(unsigned long size)
{
xms_node_t *node=NULL;
xms_node_t *t1;
-
+
if ( size <= xms_head.avail )
{
// look for existing node
else
t1=t1->next;
}
-
+
if ( node == NULL ) // didn't find existing node
{
node=malloc(sizeof(xms_node_t));
}
}
else
- pr2("out of near mem in qalloc_xms");
+ printf("out of near mem in qalloc_xms");
}
}
else
- pr2("out of xms mem in qalloc size %lu avail %lu", size, xms_head.avail);
-
+ printf("out of xms mem in qalloc size %lu avail %lu", size,
+xms_head.avail);
+
return(node);
}
-
+
+
/* ---------------------- qfree_xms() --------------------- March 8,1994 */
void qfree_xms(xms_node_t *node)
{
xms_node_t *t1;
-
+
if ( xms_head.next )
{
t1=xms_head.next;
while ( t1 != node && t1 )
t1=t1->next;
-
+
if ( t1 )
{
t1->used=0;
}
else
- pr2("ERROR didn't find node qfree");
+ printf("ERROR didn't find node qfree");
}
else
{
- pr2("ATTEMPTED to qfree empty list");
+ printf("ATTEMPTED to qfree empty list");
}
}
-
+
+
+
/* ---------------------- xms_open() ---------------------- March 8,1994 */
xms_node_t *xms_open(char *file)
{
FILE *fp;
char *buffer;
unsigned long off;
-
+
fp=fopen(file, "rb");
if ( fp )
{
off=0l;
while ( (i=fread(buffer, 1, 4096, fp)) )
{
- mem_to_xms(xms_head.handle, (char far *)buffer, off+node->start, i);
+ mem_to_xms(xms_head.handle, (char far *)buffer,
+off+node->start, i);
off+=i;
}
-
+
free(buffer);
}
else
- pr2("out of mem in xms_open 1");
+ printf("out of mem in xms_open 1");
}
-
+
fclose(fp);
}
else
- pr2("ERROR opening %s in xms_open", file);
-
+ printf("ERROR opening %s in xms_open", file);
+
return(node);
}
-
+
+
/* ---------------------- xms_read() ---------------------- March 8,1994 */
short xms_read(void far *buffer, unsigned short n, xms_node_t *node)
{
-
+
if ( node->off >= node->size )
return 0;
-
+
if ( n+node->off > node->size )
n=node->size - node->off;
-
+
xms_to_mem(xms_head.handle, buffer, node->start+node->off, n);
node->off+=n;
-
+
return(n);
}
-
+
+
/* ---------------------- xms_write() ---------------------- March 8,1994 */
short xms_write(void far *buffer, unsigned short n, xms_node_t *node)
{
-
+
if ( node->off >= node->size )
return 0;
-
+
if ( n+node->off > node->size )
n=node->size - node->off;
-
+
mem_to_xms(xms_head.handle, buffer, node->start+node->off, n);
node->off+=n;
-
+
return(n);
}
-
-
+
+
/* ---------------------- xms_tell() ---------------------- March 8,1994 */
long xms_tell(xms_node_t *node)
{
return node->off;
}
-
+
+
+
/* ---------------------- xms_seek() ---------------------- March 8,1994 */
short xms_seek(xms_node_t *node, long off, short whence)
{
short err=0;
-
+
switch ( whence )
{
case SEEK_SET:
else
node->off=off;
break;
-
+
case SEEK_END:
if ( off > 0l || (node->size + off) < 0l )
err=1;
else
node->off=node->size + off;
break;
-
+
case SEEK_CUR:
if ( node->off + off < 0l || node->off + off > node->size )
err=1;
node->off+=off;
break;
}
-
+
return(err);
}
-
+
+
/* ---------------------- xms_close() --------------------- March 8,1994 */
void xms_close(xms_node_t *node)
{
qfree_xms(node);
}
-
+
+
+
+
/* ---------------------- init_xms() ---------------------- March 8,1994 */
short init_xms(unsigned short min_blocks)
{
unsigned short blocks;
-
+
blocks=XMSblk_available();
if ( blocks >= min_blocks )
{
memset(&xms_head, 0, sizeof(xms_head_t));
if ( (xms_head.handle=alloc_xms(&blocks)) )
{
- pr2("blocks minus by = %u", blocks);
+ printf("blocks minus by = %u", blocks);
min_blocks-=blocks;
xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK;
blocks=min_blocks;
}
else
blocks=0;
-
+
return(blocks);
}
-
+
+
/* ---------------------- deinit_xms() -------------------- March 8,1994 */
void deinit_xms(void)
{
xms_node_t *t1, *t2;
-
+
if ( xms_head.handle )
{
XMS_dealloc(xms_head.handle);
t2=t1->next;
}
}
-
+
memset(&xms_head, 0, sizeof(xms_head_t));
}
}
+
+
+
/* --------------------------- end of file ------------------------- */
-/*
-
-Not sure how to use this?
-
-call init_xms(x) to allocate a big chunk of xms.
-x is in 'blocks' of 16Kb. Pick X big enough to buffer all the files
-you want to place in xms.
-
-call xms_open("filename); for each file to be buffered. This copies the file
-int xms.
-
-then use xms_read(), xms_write(), and xms_seek() to read the file from
-xms instead of disk.
-
-call deinit_xms() just before exit to clean up.
-
-You can also use the lower level calls directly.
-
+/*\r
+\r
+Not sure how to use this?\r
+\r
+call init_xms(x) to allocate a big chunk of xms.\r
+x is in 'blocks' of 16Kb. Pick X big enough to buffer all the files\r
+you want to place in xms.\r
+\r
+call xms_open("filename); for each file to be buffered. This copies the file\r
+int xms.\r
+\r
+then use xms_read(), xms_write(), and xms_seek() to read the file from\r
+xms instead of disk.\r
+\r
+call deinit_xms() just before exit to clean up.\r
+\r
+You can also use the lower level calls directly.\r
+\r
*/
+++ /dev/null
-/*
- Written by Alexander J. Russell 1994
-
- Placed in the public Domain by Alec Russell, March 1995
-
- Slightly higher level xms calls than xmem.asm
-
-*/
-
-#include <stdio.h>
-#include <io.h>
-#include <string.h>
-#include <malloc.h>
-
-#include "src\lib\xmem\xmem.h"
-
-xms_head_t xms_head={0}; // set handle to zero
-
-
-/* ---------------------- alloc_xms() ----------------- February 19,1994 */
-short alloc_xms(unsigned short far *size) // size in 16k blocks
-{
- return(XMS_alloc(0, size));
-}
-
-
-
-/* ---------------------- xms_to_mem() ---------------- February 19,1994 */
-short xms_to_mem(unsigned short handle, void far *p, unsigned long off,
-unsigned short n)
-{
- unsigned short block, boff;
-
- block=off >> XMSBLOCKSHIFT;
- boff=off - (block << XMSBLOCKSHIFT);
-
- return(XMStoMem(handle, block, boff, n, p));
-}
-
-
-/* ---------------------- mem_to_xms() ---------------- February 19,1994 */
-short mem_to_xms(unsigned short handle, void far *p, unsigned long off,
-unsigned short n)
-{
- unsigned short block, boff;
-
- block=off >> XMSBLOCKSHIFT;
- boff=off - (block << XMSBLOCKSHIFT);
-
- return(MemToXMS(handle, block, boff, n, p));
-}
-
-
-/* ---------------------- qalloc_xms() -------------------- March 8,1994 */
-xms_node_t *qalloc_xms(unsigned long size)
-{
- xms_node_t *node=NULL;
- xms_node_t *t1;
-
- if ( size <= xms_head.avail )
- {
- // look for existing node
- t1=xms_head.next;
- while ( t1 )
- {
- if ( t1->used == 0 && t1->size >= size )
- {
- t1->off=0;
- t1->used=1;
- node=t1;
- break;
- }
- else
- t1=t1->next;
- }
-
- if ( node == NULL ) // didn't find existing node
- {
- node=malloc(sizeof(xms_node_t));
- if ( node )
- {
- node->off=0;
- node->used=1;
- node->size=size;
- node->next=NULL;
- node->start=xms_head.next_off;
- xms_head.avail-=size;
- xms_head.next_off+=size;
- if ( xms_head.next == NULL )
- {
- xms_head.next=node;
- }
- else
- {
- t1=xms_head.next;
- while ( t1->next )
- t1=t1->next;
- t1->next=node;
- }
- }
- else
- printf("out of near mem in qalloc_xms");
- }
- }
- else
- printf("out of xms mem in qalloc size %lu avail %lu", size,
-xms_head.avail);
-
- return(node);
-}
-
-
-/* ---------------------- qfree_xms() --------------------- March 8,1994 */
-void qfree_xms(xms_node_t *node)
-{
- xms_node_t *t1;
-
- if ( xms_head.next )
- {
- t1=xms_head.next;
- while ( t1 != node && t1 )
- t1=t1->next;
-
- if ( t1 )
- {
- t1->used=0;
- }
- else
- printf("ERROR didn't find node qfree");
- }
- else
- {
- printf("ATTEMPTED to qfree empty list");
- }
-}
-
-
-
-/* ---------------------- xms_open() ---------------------- March 8,1994 */
-xms_node_t *xms_open(char *file)
-{
- int i;
- xms_node_t *node=NULL;
- FILE *fp;
- char *buffer;
- unsigned long off;
-
- fp=fopen(file, "rb");
- if ( fp )
- {
- node=qalloc_xms(filelength(fileno(fp)));
- if ( node )
- {
- buffer=malloc(4096);
- if ( buffer )
- {
- off=0l;
- while ( (i=fread(buffer, 1, 4096, fp)) )
- {
- mem_to_xms(xms_head.handle, (char far *)buffer,
-off+node->start, i);
- off+=i;
- }
-
- free(buffer);
- }
- else
- printf("out of mem in xms_open 1");
- }
-
- fclose(fp);
- }
- else
- printf("ERROR opening %s in xms_open", file);
-
- return(node);
-}
-
-
-/* ---------------------- xms_read() ---------------------- March 8,1994 */
-short xms_read(void far *buffer, unsigned short n, xms_node_t *node)
-{
-
- if ( node->off >= node->size )
- return 0;
-
- if ( n+node->off > node->size )
- n=node->size - node->off;
-
- xms_to_mem(xms_head.handle, buffer, node->start+node->off, n);
- node->off+=n;
-
- return(n);
-}
-
-
-/* ---------------------- xms_write() ---------------------- March 8,1994 */
-short xms_write(void far *buffer, unsigned short n, xms_node_t *node)
-{
-
- if ( node->off >= node->size )
- return 0;
-
- if ( n+node->off > node->size )
- n=node->size - node->off;
-
- mem_to_xms(xms_head.handle, buffer, node->start+node->off, n);
- node->off+=n;
-
- return(n);
-}
-
-
-/* ---------------------- xms_tell() ---------------------- March 8,1994 */
-long xms_tell(xms_node_t *node)
-{
- return node->off;
-}
-
-
-
-/* ---------------------- xms_seek() ---------------------- March 8,1994 */
-short xms_seek(xms_node_t *node, long off, short whence)
-{
- short err=0;
-
- switch ( whence )
- {
- case SEEK_SET:
- if ( off < 0l || off > node->size )
- err=1;
- else
- node->off=off;
- break;
-
- case SEEK_END:
- if ( off > 0l || (node->size + off) < 0l )
- err=1;
- else
- node->off=node->size + off;
- break;
-
- case SEEK_CUR:
- if ( node->off + off < 0l || node->off + off > node->size )
- err=1;
- else
- node->off+=off;
- break;
- }
-
- return(err);
-}
-
-
-/* ---------------------- xms_close() --------------------- March 8,1994 */
-void xms_close(xms_node_t *node)
-{
- qfree_xms(node);
-}
-
-
-
-
-/* ---------------------- init_xms() ---------------------- March 8,1994 */
-short init_xms(unsigned short min_blocks)
-{
- unsigned short blocks;
-
- blocks=XMSblk_available();
- if ( blocks >= min_blocks )
- {
- memset(&xms_head, 0, sizeof(xms_head_t));
- if ( (xms_head.handle=alloc_xms(&blocks)) )
- {
- printf("blocks minus by = %u", blocks);
- min_blocks-=blocks;
- xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK;
- blocks=min_blocks;
- }
- else
- blocks=0;
- }
- else
- blocks=0;
-
- return(blocks);
-}
-
-
-/* ---------------------- deinit_xms() -------------------- March 8,1994 */
-void deinit_xms(void)
-{
- xms_node_t *t1, *t2;
-
- if ( xms_head.handle )
- {
- XMS_dealloc(xms_head.handle);
- if ( xms_head.next )
- {
- t1=xms_head.next;
- t2=t1->next;
- while ( t1 )
- {
- free(t1);
- t1=t2;
- t2=t1->next;
- }
- }
-
- memset(&xms_head, 0, sizeof(xms_head_t));
- }
-}
-
-
-
-/* --------------------------- end of file ------------------------- */