1 /****************************************************************************
3 * SciTech OS Portability Manager Library
5 * ========================================================================
7 * The contents of this file are subject to the SciTech MGL Public
8 * License Version 1.0 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.scitechsoft.com/mgl-license.txt
12 * Software distributed under the License is distributed on an
13 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
25 * Environment: 32-bit OS/2
27 * Description: Implementation for the OS Portability Manager Library, which
28 * contains functions to implement OS specific services in a
29 * generic, cross platform API. Porting the OS Portability
30 * Manager library is the first step to porting any SciTech
31 * products to a new platform.
33 ****************************************************************************/
36 #include "drvlib/os/os.h"
46 #define INCL_DOSERRORS
53 /* Semaphore for communication with our background daemon */
54 #define SHAREDSEM ((PSZ)"\\SEM32\\SDD\\DAEMON")
55 #define DAEMON_NAME "SDDDAEMN.EXE"
57 /*--------------------------- Global variables ----------------------------*/
59 /* Public structures used to communicate with VIDEOPMI for implementing
60 * the ability to call the real mode BIOS functions.
63 typedef struct _VIDEOMODEINFO {
66 USHORT usInt10ModeSet;
69 ULONG ulBufferAddress;
75 USHORT usBytesPerScanLine;
84 CHAR bRedFieldPosition;
86 CHAR bGreenFieldPosition;
88 CHAR bBlueFieldPosition;
90 CHAR bRsvdFieldPosition;
93 } VIDEOMODEINFO, FAR *PVIDEOMODEINFO;
95 typedef struct _ADAPTERINFO {
97 CHAR szOEMString[128];
98 CHAR szDACString[128];
101 ULONG ulMMIOBaseAddress;
102 ULONG ulPIOBaseAddress;
105 USHORT usDeviceBusID;
106 USHORT usVendorBusID;
108 } ADAPTERINFO, FAR *PADAPTERINFO;
110 typedef struct _VIDEO_ADAPTER {
113 VIDEOMODEINFO ModeInfo;
114 } VIDEO_ADAPTER, FAR *PVIDEO_ADAPTER;
116 /* PMIREQUEST_SOFTWAREINT structures from OS/2 DDK */
119 ULONG ulFlags; // VDM initialization type
120 #define VDM_POSTLOAD 0x1 // adapter just loaded, used internally for initialization
121 #define VDM_INITIALIZE 0x2 // force initialization of a permanently open VDM, even if previously initialized
122 #define VDM_TERMINATE_POSTINITIALIZE 0x6 //start VDM with initialization, but close it afterwards (includes VDM_INITIALIZE)
123 #define VDM_QUERY_CAPABILITY 0x10 // query the current int 10 capability
124 #define VDM_FULL_VDM_CREATED 0x20 // a full VDM is created
125 #define VDM_MINI_VDM_CREATED 0x40 // a mini VDM is created
126 #define VDM_MINI_VDM_SUPPORTED 0x80 // mini VDM support is available
127 PCHAR szName; // VDM initialization program
128 PCHAR szArgs; // VDM initialization arguments
133 #define BUFFER_NONE 0
134 #define INPUT_BUFFER 1
135 #define OUTPUT_BUFFER 2
143 typedef struct vcrf_s {
168 #define PMIREQUEST_LOADPMIFILE 21
169 #define PMIREQUEST_IDENTIFYADAPTER 22
170 #define PMIREQUEST_SOFTWAREINT 23
172 #ifdef PTR_DECL_IN_FRONT
173 #define EXPENTRYP * EXPENTRY
175 #define EXPENTRYP EXPENTRY *
178 /* Entry point to VIDEOPMI32Request. This may be overridden by external
179 * code that has already loaded VIDEOPMI to avoid loading it twice.
182 APIRET (EXPENTRYP PM_VIDEOPMI32Request)(PVIDEO_ADAPTER, ULONG, PVOID, PVOID) = NULL;
183 static ibool haveInt10 = -1; /* True if we have Int 10 support */
184 static ibool useVPMI = true; /* False if VIDEOPMI unavailable */
185 static VIDEO_ADAPTER Adapter; /* Video adapter for VIDEOPMI */
186 static uchar RMBuf[1024]; /* Fake real mode transfer buffer */
187 static uint VESABuf_len = 1024;/* Length of the VESABuf buffer */
188 static void *VESABuf_ptr = NULL;/* Near pointer to VESABuf */
189 static uint VESABuf_rseg; /* Real mode segment of VESABuf */
190 static uint VESABuf_roff; /* Real mode offset of VESABuf */
191 static uchar * lowMem = NULL;
192 static ibool isSessionSwitching = false;
193 static ulong parmsIn[4]; /* Must not cross 64Kb boundary! */
194 static ulong parmsOut[4]; /* Must not cross 64Kb boundary! */
195 extern ushort _PM_gdt;
196 static void (PMAPIP fatalErrorCleanup)(void) = NULL;
198 /* DosSysCtl prototype. It is not declared in the headers but it is in the
199 * standard import libraries (DOSCALLS.876). Funny.
201 APIRET APIENTRY DosSysCtl(ULONG ulFunction, PVOID pvData);
203 /* This is the stack size for the threads that track the session switch event */
204 #define SESSION_SWITCH_STACK_SIZE 32768
210 UCHAR FrameBuffer[1];
213 typedef struct _SESWITCHREC {
214 /* The following variable is volatile because of PM_SUSPEND_APP */
215 volatile int Flags; /* -1 or PM_DEACTIVATE or PM_REACTIVATE */
216 PM_saveState_cb Callback; /* Save/restore context callback */
217 HMTX Mutex; /* Exclusive access mutex */
218 HEV Event; /* Posted after callback is called */
221 // Page sized block cache
223 #define PAGES_PER_BLOCK 32
224 #define PAGE_BLOCK_SIZE (PAGES_PER_BLOCK * PM_PAGE_SIZE + (PM_PAGE_SIZE-1) + sizeof(pageblock))
225 #define FREELIST_NEXT(p) (*(void**)(p))
226 typedef struct pageblock {
227 struct pageblock *next;
228 struct pageblock *prev;
233 PM_lockHandle lockHandle;
236 static pageblock *pageBlocks = NULL;
238 /*----------------------------- Implementation ----------------------------*/
240 /****************************************************************************
242 func - Helper device driver function to call
245 First return value from the device driver in parmsOut[0]
248 Function to open our helper device driver, call it and close the file
249 handle. Note that we have to open the device driver for every call because
252 1. We cannot open a single file handle in a DLL that is shared amongst
253 programs, since every process must have it's own open file handle.
255 2. For some reason there appears to be a limit of about 12 open file
256 handles on a device driver in the system. Hence when we open more
257 than about 12 file handles things start to go very strange.
259 Hence we simply open the file handle every time that we need to call the
260 device driver to work around these problems.
261 ****************************************************************************/
262 static ulong CallSDDHelp(
265 static ulong inLen; /* Must not cross 64Kb boundary! */
266 static ulong outLen; /* Must not cross 64Kb boundary! */
271 if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0,
272 FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
274 if (rc == 4) { /* Did we run out of file handles? */
278 if (DosSetRelMaxFH(&lAddFHs, &ulNewFHs) != 0)
279 PM_fatalError("Failed to raise the file handles limit!");
281 if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0,
282 FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
284 PM_fatalError("Unable to open SDDHELP$ helper device driver! (#2)");
289 PM_fatalError("Unable to open SDDHELP$ helper device driver!");
291 if (DosDevIOCtl(hSDDHelp,PMHELP_IOCTL,func,
292 &parmsIn, inLen = sizeof(parmsIn), &inLen,
293 &parmsOut, outLen = sizeof(parmsOut), &outLen) != 0)
294 PM_fatalError("Failure calling SDDHELP$ helper device driver!");
299 /****************************************************************************
301 Determine if we're running on a DBCS system.
302 ****************************************************************************/
303 ibool __IsDBCSSystem(void)
305 CHAR achDBCSInfo[12];
306 COUNTRYCODE ccStruct = {0, 0};
308 memset(achDBCSInfo, 0, 12);
310 /* Get the DBCS vector - if it's not empty, we're on DBCS */
311 DosQueryDBCSEnv(sizeof(achDBCSInfo), &ccStruct, achDBCSInfo);
312 if (achDBCSInfo[0] != 0)
318 /****************************************************************************
320 Determine if PMSHELL is running - if it isn't, we can't use certain calls
321 ****************************************************************************/
322 ibool __isShellLoaded(void)
326 if (DosGetNamedSharedMem(&ptr, (PSZ)"\\SHAREMEM\\PMGLOBAL.MEM", PAG_READ) == NO_ERROR) {
333 /****************************************************************************
335 Initialise the PM library and connect to our helper device driver. If we
336 cannot connect to our helper device driver, we bail out with an error
338 ****************************************************************************/
339 void PMAPI PM_init(void)
342 /* Obtain the 32->16 callgate from the device driver to enable IOPL */
343 if ((_PM_gdt = CallSDDHelp(PMHELP_GETGDT32)) == 0)
344 PM_fatalError("Unable to obtain call gate selector!");
348 /* Map the first Mb of physical memory into lowMem */
349 if ((lowMem = PM_mapPhysicalAddr(0,0xFFFFF,true)) == NULL)
350 PM_fatalError("Unable to map first Mb physical memory!");
352 /* Initialise the MTRR interface functions */
357 /****************************************************************************
359 Initialise the PM library for BIOS access via VIDEOPMI. This should work
360 with any GRADD driver, including SDD/2.
361 ****************************************************************************/
362 static ibool InitInt10(void)
364 HMODULE hModGENPMI,hModSDDPMI,hModVideoPMI;
365 CHAR buf[80],path[_MAX_PATH];
366 HEV hevDaemon = NULLHANDLE;
367 RESULTCODES resCodes;
369 if (haveInt10 == -1) {
370 /* Connect to VIDEOPMI and get entry point. Note that we only
371 * do this if GENPMI or SDDPMI are already loaded, since we need
372 * a GRADD based driver for this to work.
376 if (DosQueryModuleHandle((PSZ)"GENPMI.DLL",&hModGENPMI) != 0)
377 hModGENPMI = NULLHANDLE;
378 if (DosQueryModuleHandle((PSZ)"SDDPMI.DLL",&hModSDDPMI) != 0)
379 hModSDDPMI = NULLHANDLE;
380 if (hModGENPMI || hModSDDPMI) {
381 if (DosLoadModule((PSZ)buf,sizeof(buf),(PSZ)"VIDEOPMI.DLL",&hModVideoPMI) == 0) {
382 if (DosQueryProcAddr(hModVideoPMI,0,(PSZ)"VIDEOPMI32Request",(void*)&PM_VIDEOPMI32Request) != 0)
383 PM_fatalError("Unable to get VIDEOPMI32Request entry point!");
384 strcpy(path,"X:\\OS2\\SVGADATA.PMI");
385 path[0] = PM_getBootDrive();
386 if (PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_LOADPMIFILE,path,NULL) != 0) {
387 DosFreeModule(hModVideoPMI);
388 PM_VIDEOPMI32Request = NULL;
392 /* Attempt to initialise the full VDM in the system. This will only
393 * work if VPRPMI.SYS is loaded, but it provides support for passing
394 * values in ES/DS/ESI/EDI between the BIOS which does not work with
395 * kernel VDM's in fixpacks earlier than FP15. FP15 and later and
396 * the new Warp 4.51 and Warp Server convenience packs should work
397 * fine with the kernel mini-VDM.
399 * Also the full VDM is the only solution for really old kernels
400 * (but GRADD won't run on them so this is superfluous ;-).
402 INITVDM InitVDM = {VDM_INITIALIZE,NULL,NULL};
403 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&InitVDM,NULL);
409 /* A GRADD driver isn't loaded, hence we can't use VIDEOPMI. But we will try
410 * to access the mini-VDM directly, first verifying that the support is
411 * available in the kernel (it should be for kernels that support GRADD).
412 * This may be needed in a command line boot or if non-GRADD driver is
413 * used (Matrox or classic VGA).
414 * Note: because of problems with mini-VDM support in the kernel, we have to
415 * spawn a daemon process that will do the actual mini-VDM access for us.
417 /* Try to open shared semaphore to see if our daemon is already up */
418 if (DosOpenEventSem(SHAREDSEM, &hevDaemon) == NO_ERROR) {
419 if (DosWaitEventSem(hevDaemon, 1) == NO_ERROR) {
420 /* If semaphore is posted, all is well */
426 /* Create shared event semaphore */
427 if (DosCreateEventSem(SHAREDSEM, &hevDaemon, DC_SEM_SHARED, FALSE) == NO_ERROR) {
428 PM_findBPD(DAEMON_NAME, path);
429 strcat(path, DAEMON_NAME);
430 if (DosExecPgm(buf, sizeof(buf), EXEC_BACKGROUND, (PSZ)DAEMON_NAME,
431 NULL, &resCodes, (PSZ)path) == NO_ERROR) {
432 /* The daemon was successfully spawned, now give it a sec to come up */
433 if (DosWaitEventSem(hevDaemon, 2000) == NO_ERROR) {
446 /****************************************************************************
448 We "probably" have BIOS access under OS/2 but we have to verify/initialize it
450 ****************************************************************************/
451 ibool PMAPI PM_haveBIOSAccess(void)
456 /****************************************************************************
458 Return the operating system type identifier.
459 ****************************************************************************/
460 long PMAPI PM_getOSType(void)
465 /****************************************************************************
467 Return the runtime type identifier.
468 ****************************************************************************/
469 int PMAPI PM_getModeType(void)
474 /****************************************************************************
476 Add a file directory separator to the end of the filename.
477 ****************************************************************************/
478 void PMAPI PM_backslash(
481 uint pos = strlen(s);
482 if (s[pos-1] != '\\') {
488 /****************************************************************************
490 Add a user defined PM_fatalError cleanup function.
491 ****************************************************************************/
492 void PMAPI PM_setFatalErrorCleanup(
493 void (PMAPIP cleanup)(void))
495 fatalErrorCleanup = cleanup;
498 /****************************************************************************
500 Report a fatal error condition and halt the program.
501 ****************************************************************************/
502 void PMAPI PM_fatalError(
505 /* Be prepare to be called recursively (failed to fail situation :-) */
506 static int fatalErrorCount = 0;
507 if (fatalErrorCount++ == 0) {
508 if (fatalErrorCleanup)
511 fprintf(stderr,"%s\n", msg);
515 /****************************************************************************
517 Allocate the real mode VESA transfer buffer for communicating with the BIOS.
518 ****************************************************************************/
519 void * PMAPI PM_getVESABuf(
525 /* Allocate a global buffer for communicating with the VESA VBE */
526 if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL)
530 *rseg = VESABuf_rseg;
531 *roff = VESABuf_roff;
535 /****************************************************************************
537 Check if a key has been pressed.
538 ****************************************************************************/
539 int PMAPI PM_kbhit(void)
541 KBDKEYINFO key; /* Must not cross a 64K boundary */
544 return (key.fbStatus & KBDTRF_FINAL_CHAR_IN);
547 /****************************************************************************
549 Wait for and return the next keypress.
550 ****************************************************************************/
551 int PMAPI PM_getch(void)
553 KBDKEYINFO key; /* Must not cross a 64K boundary */
555 KbdCharIn(&key,IO_WAIT,0);
559 /****************************************************************************
561 Open a fullscreen console for output to the screen. This requires that
562 the application be a fullscreen VIO program.
563 ****************************************************************************/
564 PM_HWND PMAPI PM_openConsole(
581 /****************************************************************************
583 Find the size of the console state buffer.
584 ****************************************************************************/
585 int PMAPI PM_getConsoleStateSize(void)
588 vmi.cb = sizeof (VIOMODEINFO);
589 VioGetMode (&vmi, (HVIO)0);
590 return sizeof (CONSOLE_SAVE) - 1 + vmi.col * vmi.row * 2;
593 /****************************************************************************
595 Save the state of the console.
596 ****************************************************************************/
597 void PMAPI PM_saveConsoleState(
602 CONSOLE_SAVE *cs = (CONSOLE_SAVE*)stateBuf;
605 /* The reason for the VIOMODEINFO juggling is 16-bit code. Because the user
606 * allocates the state buffer, cd->vmi might be crossing the 64K boundary and
607 * the 16-bit API would fail. If we create another copy on stack, the compiler
608 * should ensure that the 64K boundary will not be crossed (it adjusts the stack
609 * if it should cross).
611 vmi.cb = sizeof(VIOMODEINFO);
612 VioGetMode(&vmi,(HVIO)0);
613 memcpy(&cs->vmi, &vmi, sizeof(VIOMODEINFO));
614 VioGetCurPos(&cs->CursorY, &cs->CursorX, (HVIO)0);
615 fblen = cs->vmi.col * cs->vmi.row * 2;
616 VioReadCellStr((PCH)cs->FrameBuffer, &fblen, 0, 0, (HVIO)0);
619 /* Global variable to communicate between threads */
620 static SESWITCHREC SesSwitchRec = { -1 };
622 /****************************************************************************
624 Called by external routines at least once per frame to check whenever a
625 session save/restore should be performed. Since we receive such notifications
626 asyncronously, we can't perform all required operations at that time.
627 ****************************************************************************/
628 void __PM_checkConsoleSwitch(void)
631 PM_saveState_cb Callback;
633 /* Quick optimized path for most common case */
634 if (SesSwitchRec.Flags == -1)
638 if (DosRequestMutexSem(SesSwitchRec.Mutex, 100))
640 Flags = SesSwitchRec.Flags;
641 Callback = SesSwitchRec.Callback;
642 SesSwitchRec.Flags = -1;
643 DosReleaseMutexSem(SesSwitchRec.Mutex);
645 isSessionSwitching = true; /* Prevent VIO calls */
646 Mode = Callback(Flags);
647 isSessionSwitching = false;
648 DosPostEventSem(SesSwitchRec.Event);
649 if (Flags == PM_DEACTIVATE && Mode == PM_SUSPEND_APP)
650 /* Suspend application until we switch back to our application */
653 /* SesSwitchRec.Flags is volatile so optimizer
654 * won't load it into a register
656 if (SesSwitchRec.Flags != -1)
661 /****************************************************************************
663 Waits until main thread processes the session switch event.
664 ****************************************************************************/
665 static void _PM_SessionSwitchEvent(
666 PM_saveState_cb saveState,
671 if (DosRequestMutexSem(SesSwitchRec.Mutex, 10000))
674 /* We're going to wait on that semaphore */
675 DosResetEventSem(SesSwitchRec.Event, &Count);
676 SesSwitchRec.Callback = saveState;
677 SesSwitchRec.Flags = flags;
678 DosReleaseMutexSem(SesSwitchRec.Mutex);
680 /* Now wait until all required operations are complete */
681 DosWaitEventSem (SesSwitchRec.Event, 10000);
684 /****************************************************************************
686 This is the thread responsible for tracking switches back to our
688 ****************************************************************************/
689 static void _PM_ConsoleSwitch(
690 PM_saveState_cb saveState)
695 if (VioModeWait(VMWR_POPUP, &NotifyType, 0) != 0)
697 _PM_SessionSwitchEvent(saveState, PM_REACTIVATE);
699 VioModeUndo(UNDOI_RELEASEOWNER, UNDOK_ERRORCODE, (HVIO)0);
702 /****************************************************************************
704 This is the thread responsible for tracking screen popups (usually fatal
705 error handler uses them).
706 ****************************************************************************/
707 static void _PM_ConsolePopup(
708 PM_saveState_cb saveState)
712 if (VioSavRedrawWait(VSRWI_SAVEANDREDRAW, &NotifyType, 0) != 0)
714 if (NotifyType == VSRWN_SAVE)
715 _PM_SessionSwitchEvent(saveState, PM_DEACTIVATE);
716 else if (NotifyType == VSRWN_REDRAW)
717 _PM_SessionSwitchEvent(saveState, PM_REACTIVATE);
719 VioSavRedrawUndo(UNDOI_RELEASEOWNER, UNDOK_ERRORCODE, (HVIO)0);
722 /****************************************************************************
724 Set the suspend application callback for the fullscreen console.
725 ****************************************************************************/
726 void PMAPI PM_setSuspendAppCallback(
727 PM_saveState_cb saveState)
729 // If PM isn't loaded, this stuff will cause crashes!
730 if (__isShellLoaded()) {
732 /* Create the threads responsible for tracking console switches */
733 SesSwitchRec.Flags = -1;
734 DosCreateMutexSem(NULL, &SesSwitchRec.Mutex, 0, FALSE);
735 DosCreateEventSem(NULL, &SesSwitchRec.Event, 0, FALSE);
736 _beginthread ((void(*)(void*))_PM_ConsoleSwitch,NULL,SESSION_SWITCH_STACK_SIZE, (void*)saveState);
737 _beginthread ((void(*)(void*))_PM_ConsolePopup,NULL,SESSION_SWITCH_STACK_SIZE, (void*)saveState);
740 /* Kill the threads responsible for tracking console switches */
741 VioModeUndo(UNDOI_RELEASEOWNER, UNDOK_TERMINATE, (HVIO)0);
742 VioSavRedrawUndo(UNDOI_RELEASEOWNER, UNDOK_TERMINATE, (HVIO)0);
743 DosCloseEventSem(SesSwitchRec.Event);
744 DosCloseMutexSem(SesSwitchRec.Mutex);
749 /****************************************************************************
751 Restore the console state.
752 ****************************************************************************/
753 void PMAPI PM_restoreConsoleState(
754 const void *stateBuf,
757 CONSOLE_SAVE *cs = (CONSOLE_SAVE *)stateBuf;
763 memcpy(&vmi, &cs->vmi, sizeof (VIOMODEINFO));
764 VioSetMode(&vmi, (HVIO)0);
765 VioSetCurPos(cs->CursorY, cs->CursorX, (HVIO)0);
766 VioWrtCellStr((PCH)cs->FrameBuffer, cs->vmi.col * cs->vmi.row * 2,0, 0, (HVIO)0);
769 /****************************************************************************
771 Close the fullscreen console.
772 ****************************************************************************/
773 void PMAPI PM_closeConsole(
776 /* Kill the threads responsible for tracking console switches */
777 PM_setSuspendAppCallback(NULL);
781 /****************************************************************************
783 Set the location of the OS console cursor.
784 ****************************************************************************/
785 void PM_setOSCursorLocation(
789 /* If session switch is in progress, calling into VIO causes deadlocks! */
790 /* Also this call to VIO screws up our console library on DBCS boxes... */
791 if (!isSessionSwitching && !__IsDBCSSystem())
795 /****************************************************************************
797 Set the width of the OS console.
798 ****************************************************************************/
799 void PM_setOSScreenWidth(
803 /* Nothing to do in here */
808 /****************************************************************************
810 Set the real time clock handler (used for software stereo modes).
811 ****************************************************************************/
812 ibool PMAPI PM_setRealTimeClockHandler(
816 // TODO: Implement this!
822 /****************************************************************************
824 Set the real time clock frequency (for stereo modes).
825 ****************************************************************************/
826 void PMAPI PM_setRealTimeClockFrequency(
829 // TODO: Implement this!
833 /****************************************************************************
835 Restore the original real time clock handler.
836 ****************************************************************************/
837 void PMAPI PM_restoreRealTimeClockHandler(void)
839 // TODO: Implement this!
842 /****************************************************************************
844 Return the current operating system path or working directory.
845 ****************************************************************************/
846 char * PMAPI PM_getCurrentPath(
850 return getcwd(path,maxLen);
853 /****************************************************************************
855 Return the drive letter for the boot drive.
856 ****************************************************************************/
857 char PMAPI PM_getBootDrive(void)
860 DosQuerySysInfo(QSV_BOOT_DRIVE,QSV_BOOT_DRIVE,&boot,sizeof(boot));
861 return (char)('a' + boot - 1);
864 /****************************************************************************
866 Return the path to the VBE/AF driver files.
867 ****************************************************************************/
868 const char * PMAPI PM_getVBEAFPath(void)
870 static char path[CCHMAXPATH];
872 path[0] = PM_getBootDrive();
876 /****************************************************************************
878 Return the path to the Nucleus driver files.
879 ****************************************************************************/
880 const char * PMAPI PM_getNucleusPath(void)
882 static char path[CCHMAXPATH];
883 if (getenv("NUCLEUS_PATH") != NULL)
884 return getenv("NUCLEUS_PATH");
885 strcpy(path,"x:\\os2\\drivers");
886 path[0] = PM_getBootDrive();
888 strcat(path,"nucleus");
892 /****************************************************************************
894 Return the path to the Nucleus configuration files.
895 ****************************************************************************/
896 const char * PMAPI PM_getNucleusConfigPath(void)
898 static char path[CCHMAXPATH];
899 strcpy(path,PM_getNucleusPath());
901 strcat(path,"config");
905 /****************************************************************************
907 Return a unique identifier for the machine if possible.
908 ****************************************************************************/
909 const char * PMAPI PM_getUniqueID(void)
911 return PM_getMachineName();
914 /****************************************************************************
916 Get the name of the machine on the network.
917 ****************************************************************************/
918 const char * PMAPI PM_getMachineName(void)
920 static char name[40],*env;
922 if ((env = getenv("HOSTNAME")) != NULL) {
923 strncpy(name,env,sizeof(name));
924 name[sizeof(name)-1] = 0;
930 /****************************************************************************
932 Return a pointer to the real mode BIOS data area.
933 ****************************************************************************/
934 void * PMAPI PM_getBIOSPointer(void)
937 return lowMem + 0x400;
940 /****************************************************************************
942 Return a pointer to 0xA0000 physical VGA graphics framebuffer.
943 ****************************************************************************/
944 void * PMAPI PM_getA0000Pointer(void)
947 return lowMem + 0xA0000;
950 /****************************************************************************
952 Map a physical address to a linear address in the callers process.
953 ****************************************************************************/
954 void * PMAPI PM_mapPhysicalAddr(
959 ulong baseAddr,baseOfs,linear;
961 /* Round the physical address to a 4Kb boundary and the limit to a
962 * 4Kb-1 boundary before passing the values to mmap. If we round the
963 * physical address, then we also add an extra offset into the address
966 baseOfs = base & 4095;
967 baseAddr = base & ~4095;
968 limit = ((limit+baseOfs+1+4095) & ~4095)-1;
969 parmsIn[0] = baseAddr;
971 parmsIn[2] = isCached;
972 if ((linear = CallSDDHelp(PMHELP_MAPPHYS)) == 0)
974 return (void*)(linear + baseOfs);
977 /****************************************************************************
979 Free a physical address mapping allocated by PM_mapPhysicalAddr.
980 ****************************************************************************/
981 void PMAPI PM_freePhysicalAddr(
985 parmsIn[0] = (ulong)ptr;
987 CallSDDHelp(PMHELP_FREEPHYS);
990 /****************************************************************************
992 Find the physical address of a linear memory address in current process.
993 ****************************************************************************/
994 ulong PMAPI PM_getPhysicalAddr(
997 parmsIn[0] = (ulong)p;
998 return CallSDDHelp(PMHELP_GETPHYSICALADDR);
1001 /****************************************************************************
1003 Find the physical address of a linear memory address in current process.
1004 ****************************************************************************/
1005 ibool PMAPI PM_getPhysicalAddrRange(
1010 parmsIn[0] = (ulong)p;
1011 parmsIn[1] = (ulong)length;
1012 parmsIn[2] = (ulong)physAddress;
1013 return CallSDDHelp(PMHELP_GETPHYSICALADDRRANGE);
1016 /****************************************************************************
1018 Sleep for the specified number of milliseconds.
1019 ****************************************************************************/
1020 void PMAPI PM_sleep(
1023 DosSleep(milliseconds);
1026 /****************************************************************************
1028 Return the base I/O port for the specified COM port.
1029 ****************************************************************************/
1030 int PMAPI PM_getCOMPort(
1034 case 0: return 0x3F8;
1035 case 1: return 0x2F8;
1040 /****************************************************************************
1042 Return the base I/O port for the specified LPT port.
1043 ****************************************************************************/
1044 int PMAPI PM_getLPTPort(
1048 case 0: return 0x3BC;
1049 case 1: return 0x378;
1050 case 2: return 0x278;
1055 /****************************************************************************
1057 Allocate a block of shared memory. For Win9x we allocate shared memory
1058 as locked, global memory that is accessible from any memory context
1059 (including interrupt time context), which allows us to load our important
1060 data structure and code such that we can access it directly from a ring
1061 0 interrupt context.
1062 ****************************************************************************/
1063 void * PMAPI PM_mallocShared(
1067 return (void*)CallSDDHelp(PMHELP_MALLOCSHARED);
1070 /****************************************************************************
1072 Free a block of shared memory.
1073 ****************************************************************************/
1074 void PMAPI PM_freeShared(
1077 parmsIn[0] = (ulong)ptr;
1078 CallSDDHelp(PMHELP_FREESHARED);
1081 /****************************************************************************
1083 Map a linear memory address to the calling process address space. The
1084 address will have been allocated in another process using the
1085 PM_mapPhysicalAddr function.
1086 ****************************************************************************/
1087 void * PMAPI PM_mapToProcess(
1091 ulong baseAddr,baseOfs;
1093 /* Round the physical address to a 4Kb boundary and the limit to a
1094 * 4Kb-1 boundary before passing the values to mmap. If we round the
1095 * physical address, then we also add an extra offset into the address
1098 baseOfs = (ulong)base & 4095;
1099 baseAddr = (ulong)base & ~4095;
1100 limit = ((limit+baseOfs+1+4095) & ~4095)-1;
1101 parmsIn[0] = (ulong)baseAddr;
1103 return (void*)(CallSDDHelp(PMHELP_MAPTOPROCESS)+baseOfs);
1106 /****************************************************************************
1108 Map a real mode pointer to a protected mode pointer.
1109 ****************************************************************************/
1110 void * PMAPI PM_mapRealPointer(
1114 if (r_seg == 0xFFFF)
1115 return &RMBuf[r_off];
1116 return lowMem + MK_PHYS(r_seg,r_off);
1119 /****************************************************************************
1121 Allocate a block of real mode memory
1122 ****************************************************************************/
1123 void * PMAPI PM_allocRealSeg(
1128 if (size > sizeof(RMBuf))
1135 /****************************************************************************
1137 Free a block of real mode memory.
1138 ****************************************************************************/
1139 void PMAPI PM_freeRealSeg(
1142 /* Nothing to do in here */
1146 #define INDPMI(reg) rmregs.aCRF.reg_##reg = regs->reg
1147 #define OUTDPMI(reg) regs->reg = rmregs.aCRF.reg_##reg
1149 #define REG_OFFSET(field) (((ULONG)&(((VCRF*)0)->field)) / sizeof(ULONG))
1151 /****************************************************************************
1153 Issue a real mode interrupt (parameters in DPMI compatible structure)
1154 ****************************************************************************/
1155 void PMAPI DPMI_int86(
1164 memset(&rmregs, 0, sizeof(rmregs));
1165 rmregs.ulBIOSIntNo = intno;
1166 INDPMI(eax); INDPMI(ebx); INDPMI(ecx); INDPMI(edx); INDPMI(esi); INDPMI(edi);
1167 rmregs.aCRF.reg_ds = regs->ds;
1168 rmregs.aCRF.reg_es = regs->es;
1169 if (intno == 0x10) {
1170 eax = rmregs.aCRF.reg_eax;
1171 switch (eax & 0xFFFF) {
1173 /* We have to hack the way this function works, due to
1174 * some bugs in the IBM mini-VDM BIOS support. Specifically
1175 * we need to make the input buffer and output buffer the
1176 * 'same' buffer, and that ES:SI points to the output
1177 * buffer (ignored by the BIOS). The data will end up
1178 * being returned in the input buffer, except for the
1179 * first four bytes ('VESA') that will not be returned.
1181 rmregs.pB[0].bBufferType = INPUT_BUFFER;
1182 rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
1183 rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
1184 rmregs.pB[0].pAddress = RMBuf;
1185 rmregs.pB[0].ulSize = 4;
1186 rmregs.pB[1].bBufferType = OUTPUT_BUFFER;
1187 rmregs.pB[1].bSelCRF = REG_OFFSET(reg_es);
1188 rmregs.pB[1].bOffCRF = REG_OFFSET(reg_esi);
1189 rmregs.pB[1].pAddress = ((PBYTE)RMBuf)+4;
1190 rmregs.pB[1].ulSize = 512-4;
1193 rmregs.pB[0].bBufferType = OUTPUT_BUFFER;
1194 rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
1195 rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
1196 rmregs.pB[0].pAddress = RMBuf;
1197 rmregs.pB[0].ulSize = 256;
1200 rmregs.pB[0].bBufferType = INPUT_BUFFER;
1201 rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
1202 rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
1203 rmregs.pB[0].pAddress = RMBuf;
1204 rmregs.pB[0].ulSize = 256;
1207 rmregs.pB[0].bBufferType = INPUT_BUFFER;
1208 rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
1209 rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
1210 rmregs.pB[0].pAddress = RMBuf;
1211 rmregs.pB[0].ulSize = 1024;
1214 /* Due to bugs in the mini-VDM in OS/2, the 0x4F0A protected
1215 * mode interface functions will not work (we never get any
1216 * selectors returned), so we fail this function here. The
1217 * rest of the VBE/Core driver will work properly if this
1218 * function is failed, because the VBE 2.0 and 3.0 specs
1226 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,NULL,&rmregs);
1228 DosSysCtl(6, &rmregs);
1231 OUTDPMI(eax); OUTDPMI(ebx); OUTDPMI(ecx); OUTDPMI(edx); OUTDPMI(esi); OUTDPMI(edi);
1232 if (((regs->eax & 0xFFFF) == 0x004F) && ((eax & 0xFFFF) == 0x4F00)) {
1233 /* Hack to fix up the missing 'VESA' string for mini-VDM */
1234 memcpy(RMBuf,"VESA",4);
1236 regs->ds = rmregs.aCRF.reg_ds;
1237 regs->es = rmregs.aCRF.reg_es;
1238 regs->flags = rmregs.aCRF.reg_eflag;
1241 #define IN(reg) rmregs.reg = in->e.reg
1242 #define OUT(reg) out->e.reg = rmregs.reg
1244 /****************************************************************************
1246 Issue a real mode interrupt.
1247 ****************************************************************************/
1255 memset(&rmregs, 0, sizeof(rmregs));
1256 IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1257 DPMI_int86(intno,&rmregs);
1258 OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1259 out->x.cflag = rmregs.flags & 0x1;
1263 /****************************************************************************
1265 Issue a real mode interrupt.
1266 ****************************************************************************/
1267 int PMAPI PM_int86x(
1275 memset(&rmregs, 0, sizeof(rmregs));
1276 IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1277 rmregs.es = sregs->es;
1278 rmregs.ds = sregs->ds;
1279 DPMI_int86(intno,&rmregs);
1280 OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1281 sregs->es = rmregs.es;
1282 sregs->cs = rmregs.cs;
1283 sregs->ss = rmregs.ss;
1284 sregs->ds = rmregs.ds;
1285 out->x.cflag = rmregs.flags & 0x1;
1289 /****************************************************************************
1291 Call a real mode far function.
1292 ****************************************************************************/
1293 void PMAPI PM_callRealMode(
1299 PM_fatalError("PM_callRealMode not supported on OS/2!");
1302 /****************************************************************************
1304 Return the amount of available memory.
1305 ****************************************************************************/
1306 void PMAPI PM_availableMemory(
1310 /* Unable to get reliable values from OS/2 for this */
1311 *physical = *total = 0;
1314 /****************************************************************************
1316 Allocate a block of locked, physical memory for DMA operations.
1317 ****************************************************************************/
1318 void * PMAPI PM_allocLockedMem(
1325 parmsIn[1] = contiguous;
1326 parmsIn[2] = below16M;
1327 CallSDDHelp(PMHELP_ALLOCLOCKED);
1328 *physAddr = parmsOut[1];
1329 return (void*)parmsOut[0];
1332 /****************************************************************************
1334 Free a block of locked physical memory.
1335 ****************************************************************************/
1336 void PMAPI PM_freeLockedMem(
1341 parmsIn[0] = (ulong)p;
1342 CallSDDHelp(PMHELP_FREELOCKED);
1345 /****************************************************************************
1347 Allocates a new block of pages for the page block manager.
1348 ****************************************************************************/
1349 static pageblock *PM_addNewPageBlock(void)
1352 pageblock *newBlock;
1355 /* Allocate memory for the new page block, and add to head of list */
1356 if (DosAllocSharedMem((void**)&newBlock,NULL,PAGE_BLOCK_SIZE,OBJ_GETTABLE | PAG_READ | PAG_WRITE | PAG_COMMIT))
1358 if (!PM_lockDataPages(newBlock,PAGE_BLOCK_SIZE,&newBlock->lockHandle))
1360 newBlock->prev = NULL;
1361 newBlock->next = pageBlocks;
1363 pageBlocks->prev = newBlock;
1364 pageBlocks = newBlock;
1366 /* Initialise the page aligned free list for the page block */
1367 newBlock->freeCount = PAGES_PER_BLOCK;
1368 newBlock->freeList = p = (char*)(((ulong)(newBlock + 1) + (PM_PAGE_SIZE-1)) & ~(PM_PAGE_SIZE-1));
1369 newBlock->freeListStart = newBlock->freeList;
1370 newBlock->freeListEnd = p + (PAGES_PER_BLOCK-1) * PM_PAGE_SIZE;
1371 for (i = 0; i < PAGES_PER_BLOCK; i++,p = next)
1372 FREELIST_NEXT(p) = next = p + PM_PAGE_SIZE;
1373 FREELIST_NEXT(p - PM_PAGE_SIZE) = NULL;
1377 /****************************************************************************
1379 Allocates a page aligned and page sized block of memory
1380 ****************************************************************************/
1381 void * PMAPI PM_allocPage(
1387 /* Scan the block list looking for any free blocks. Allocate a new
1388 * page block if no free blocks are found.
1390 for (block = pageBlocks; block != NULL; block = block->next) {
1391 if (block->freeCount)
1394 if (block == NULL && (block = PM_addNewPageBlock()) == NULL)
1397 p = block->freeList;
1398 block->freeList = FREELIST_NEXT(p);
1403 /****************************************************************************
1405 Free a page aligned and page sized block of memory
1406 ****************************************************************************/
1407 void PMAPI PM_freePage(
1412 /* First find the page block that this page belongs to */
1413 for (block = pageBlocks; block != NULL; block = block->next) {
1414 if (p >= block->freeListStart && p <= block->freeListEnd)
1417 CHECK(block != NULL);
1419 /* Now free the block by adding it to the free list */
1420 FREELIST_NEXT(p) = block->freeList;
1421 block->freeList = p;
1422 if (++block->freeCount == PAGES_PER_BLOCK) {
1423 /* If all pages in the page block are now free, free the entire
1424 * page block itself.
1426 if (block == pageBlocks) {
1427 /* Delete from head */
1428 pageBlocks = block->next;
1430 block->next->prev = NULL;
1433 /* Delete from middle of list */
1434 CHECK(block->prev != NULL);
1435 block->prev->next = block->next;
1437 block->next->prev = block->prev;
1440 /* Unlock the memory and free it */
1441 PM_unlockDataPages(block,PAGE_BLOCK_SIZE,&block->lockHandle);
1446 /****************************************************************************
1448 Map in all the shared memory blocks for managing the memory pages above.
1449 ****************************************************************************/
1450 void PMAPI PM_mapSharedPages(void)
1454 /* Map all the page blocks above into the shared memory for process */
1455 for (block = pageBlocks; block != NULL; block = block->next) {
1456 DosGetSharedMem(block, PAG_READ | PAG_WRITE);
1460 /****************************************************************************
1462 Lock linear memory so it won't be paged.
1463 ****************************************************************************/
1464 int PMAPI PM_lockDataPages(
1467 PM_lockHandle *lockHandle)
1469 parmsIn[0] = (ulong)p;
1471 CallSDDHelp(PMHELP_LOCKPAGES);
1472 lockHandle->h[0] = parmsOut[1];
1473 lockHandle->h[1] = parmsOut[2];
1474 lockHandle->h[2] = parmsOut[3];
1478 /****************************************************************************
1480 Unlock linear memory so it won't be paged.
1481 ****************************************************************************/
1482 int PMAPI PM_unlockDataPages(
1485 PM_lockHandle *lockHandle)
1487 parmsIn[0] = lockHandle->h[0];
1488 parmsIn[1] = lockHandle->h[1];
1489 parmsIn[2] = lockHandle->h[2];
1490 return CallSDDHelp(PMHELP_UNLOCKPAGES);
1493 /****************************************************************************
1495 Lock linear memory so it won't be paged.
1496 ****************************************************************************/
1497 int PMAPI PM_lockCodePages(
1500 PM_lockHandle *lockHandle)
1502 parmsIn[0] = (ulong)p;
1504 CallSDDHelp(PMHELP_LOCKPAGES);
1505 lockHandle->h[0] = parmsOut[1];
1506 lockHandle->h[1] = parmsOut[2];
1507 lockHandle->h[2] = parmsOut[3];
1511 /****************************************************************************
1513 Unlock linear memory so it won't be paged.
1514 ****************************************************************************/
1515 int PMAPI PM_unlockCodePages(
1518 PM_lockHandle *lockHandle)
1520 parmsIn[0] = lockHandle->h[0];
1521 parmsIn[1] = lockHandle->h[1];
1522 parmsIn[2] = lockHandle->h[2];
1523 return CallSDDHelp(PMHELP_UNLOCKPAGES);
1526 /****************************************************************************
1528 Call the VBE/Core software interrupt to change display banks.
1529 ****************************************************************************/
1530 void PMAPI PM_setBankA(
1537 memset(&rmregs, 0, sizeof(rmregs));
1538 rmregs.ulBIOSIntNo = 0x10;
1539 rmregs.aCRF.reg_eax = 0x4F05;
1540 rmregs.aCRF.reg_ebx = 0x0000;
1541 rmregs.aCRF.reg_edx = bank;
1542 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
1545 /****************************************************************************
1547 Call the VBE/Core software interrupt to change display banks.
1548 ****************************************************************************/
1549 void PMAPI PM_setBankAB(
1556 memset(&rmregs, 0, sizeof(rmregs));
1557 rmregs.ulBIOSIntNo = 0x10;
1558 rmregs.aCRF.reg_eax = 0x4F05;
1559 rmregs.aCRF.reg_ebx = 0x0000;
1560 rmregs.aCRF.reg_edx = bank;
1561 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
1562 rmregs.ulBIOSIntNo = 0x10;
1563 rmregs.aCRF.reg_eax = 0x4F05;
1564 rmregs.aCRF.reg_ebx = 0x0001;
1565 rmregs.aCRF.reg_edx = bank;
1566 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
1569 /****************************************************************************
1571 Call the VBE/Core software interrupt to change display start address.
1572 ****************************************************************************/
1573 void PMAPI PM_setCRTStart(
1582 memset(&rmregs, 0, sizeof(rmregs));
1583 rmregs.ulBIOSIntNo = 0x10;
1584 rmregs.aCRF.reg_eax = 0x4F07;
1585 rmregs.aCRF.reg_ebx = waitVRT;
1586 rmregs.aCRF.reg_ecx = x;
1587 rmregs.aCRF.reg_edx = y;
1588 PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
1591 /****************************************************************************
1593 Execute the POST on the secondary BIOS for a controller.
1594 ****************************************************************************/
1595 ibool PMAPI PM_doBIOSPOST(
1608 /****************************************************************************
1610 base - The starting physical base address of the region
1611 size - The size in bytes of the region
1612 type - Type to place into the MTRR register
1615 Error code describing the result.
1618 Function to enable write combining for the specified region of memory.
1619 ****************************************************************************/
1620 int PMAPI PM_enableWriteCombine(
1625 return MTRR_enableWriteCombine(base,size,type);
1628 // TODO: Move the MTRR helper stuff into the call gate, or better yet
1629 // entirely into the ring 0 helper driver!!
1631 /* MTRR helper functions. To make it easier to implement the MTRR support
1632 * under OS/2, we simply put our ring 0 helper functions into the
1633 * helper device driver rather than the entire MTRR module. This makes
1634 * it easier to maintain the MTRR support since we don't need to deal
1635 * with 16-bit ring 0 code in the MTRR library.
1638 /****************************************************************************
1640 Flush the translation lookaside buffer.
1641 ****************************************************************************/
1642 void PMAPI PM_flushTLB(void)
1644 CallSDDHelp(PMHELP_FLUSHTLB);
1647 /****************************************************************************
1649 Return true if ring 0 (or if we can call the helpers functions at ring 0)
1650 ****************************************************************************/
1651 ibool _ASMAPI _MTRR_isRing0(void)
1656 /****************************************************************************
1658 Read and return the value of the CR4 register
1659 ****************************************************************************/
1660 ulong _ASMAPI _MTRR_saveCR4(void)
1662 return CallSDDHelp(PMHELP_SAVECR4);
1665 /****************************************************************************
1667 Restore the value of the CR4 register
1668 ****************************************************************************/
1669 void _ASMAPI _MTRR_restoreCR4(ulong cr4Val)
1671 parmsIn[0] = cr4Val;
1672 CallSDDHelp(PMHELP_RESTORECR4);
1675 /****************************************************************************
1677 Read a machine status register for the CPU.
1678 ****************************************************************************/
1679 void _ASMAPI _MTRR_readMSR(
1685 CallSDDHelp(PMHELP_READMSR);
1690 /****************************************************************************
1692 Write a machine status register for the CPU.
1693 ****************************************************************************/
1694 void _ASMAPI _MTRR_writeMSR(
1702 CallSDDHelp(PMHELP_WRITEMSR);
1705 PM_MODULE PMAPI PM_loadLibrary(
1706 const char *szDLLName)
1708 // TODO: Implement this to load shared libraries!
1713 void * PMAPI PM_getProcAddress(
1715 const char *szProcName)
1717 // TODO: Implement this!
1723 void PMAPI PM_freeLibrary(
1726 // TODO: Implement this!
1730 /****************************************************************************
1732 Internal function to convert the find data to the generic interface.
1733 ****************************************************************************/
1734 static void convertFindData(
1735 PM_findData *findData,
1738 ulong dwSize = findData->dwSize;
1740 memset(findData,0,findData->dwSize);
1741 findData->dwSize = dwSize;
1742 if (blk->attrFile & FILE_READONLY)
1743 findData->attrib |= PM_FILE_READONLY;
1744 if (blk->attrFile & FILE_DIRECTORY)
1745 findData->attrib |= PM_FILE_DIRECTORY;
1746 if (blk->attrFile & FILE_ARCHIVED)
1747 findData->attrib |= PM_FILE_ARCHIVE;
1748 if (blk->attrFile & FILE_HIDDEN)
1749 findData->attrib |= PM_FILE_HIDDEN;
1750 if (blk->attrFile & FILE_SYSTEM)
1751 findData->attrib |= PM_FILE_SYSTEM;
1752 findData->sizeLo = blk->cbFile;
1753 findData->sizeHi = 0;
1754 strncpy(findData->name,blk->achName,PM_MAX_PATH);
1755 findData->name[PM_MAX_PATH-1] = 0;
1758 #define FIND_MASK (FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN | FILE_READONLY)
1760 /****************************************************************************
1762 Function to find the first file matching a search criteria in a directory.
1763 ****************************************************************************/
1764 void *PMAPI PM_findFirstFile(
1765 const char *filename,
1766 PM_findData *findData)
1769 HDIR hdir = HDIR_CREATE;
1772 if (DosFindFirst((PSZ)filename,&hdir,FIND_MASK,&blk,sizeof(blk),&count,FIL_STANDARD) == NO_ERROR) {
1773 convertFindData(findData,&blk);
1776 return PM_FILE_INVALID;
1779 /****************************************************************************
1781 Function to find the next file matching a search criteria in a directory.
1782 ****************************************************************************/
1783 ibool PMAPI PM_findNextFile(
1785 PM_findData *findData)
1790 if (DosFindNext((HDIR)handle,&blk,sizeof(blk),&count) == NO_ERROR) {
1791 convertFindData(findData,&blk);
1797 /****************************************************************************
1799 Function to close the find process
1800 ****************************************************************************/
1801 void PMAPI PM_findClose(
1804 DosFindClose((HDIR)handle);
1807 /****************************************************************************
1809 Function to determine if a drive is a valid drive or not. Under Unix this
1810 function will return false for anything except a value of 3 (considered
1811 the root drive, and equivalent to C: for non-Unix systems). The drive
1820 ****************************************************************************/
1821 ibool PMAPI PM_driveValid(
1824 ulong cntDisk,cntDriveMap;
1827 DosQueryCurrentDisk(&cntDisk,&cntDriveMap);
1828 valid = (DosSetDefaultDisk(drive) == NO_ERROR);
1829 DosSetDefaultDisk(cntDisk);
1833 /****************************************************************************
1835 Function to get the current working directory for the specififed drive.
1836 Under Unix this will always return the current working directory regardless
1837 of what the value of 'drive' is.
1838 ****************************************************************************/
1839 void PMAPI PM_getdcwd(
1846 DosQueryCurrentDir(drive, (PSZ)dir, &length);
1849 /****************************************************************************
1851 Function to change the file attributes for a specific file.
1852 ****************************************************************************/
1853 void PMAPI PM_setFileAttr(
1854 const char *filename,
1859 if (DosQueryPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&s,sizeof(s)))
1862 if (attrib & PM_FILE_READONLY)
1863 s.attrFile |= FILE_READONLY;
1864 if (attrib & PM_FILE_ARCHIVE)
1865 s.attrFile |= FILE_ARCHIVED;
1866 if (attrib & PM_FILE_HIDDEN)
1867 s.attrFile |= FILE_HIDDEN;
1868 if (attrib & PM_FILE_SYSTEM)
1869 s.attrFile |= FILE_SYSTEM;
1870 DosSetPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&s,sizeof(s),0L);
1873 /****************************************************************************
1875 Function to get the file attributes for a specific file.
1876 ****************************************************************************/
1877 uint PMAPI PM_getFileAttr(
1878 const char *filename)
1883 if (DosQueryPathInfo((PSZ)filename, FIL_STANDARD, &fs3, sizeof(FILESTATUS3)))
1885 if (fs3.attrFile & FILE_READONLY)
1886 retval |= PM_FILE_READONLY;
1887 if (fs3.attrFile & FILE_ARCHIVED)
1888 retval |= PM_FILE_ARCHIVE;
1889 if (fs3.attrFile & FILE_HIDDEN)
1890 retval |= PM_FILE_HIDDEN;
1891 if (fs3.attrFile & FILE_SYSTEM)
1892 retval |= PM_FILE_SYSTEM;
1896 /****************************************************************************
1898 Function to create a directory.
1899 ****************************************************************************/
1900 ibool PMAPI PM_mkdir(
1901 const char *filename)
1903 return DosCreateDir((PSZ)filename,NULL) == NO_ERROR;
1906 /****************************************************************************
1908 Function to remove a directory.
1909 ****************************************************************************/
1910 ibool PMAPI PM_rmdir(
1911 const char *filename)
1913 return DosDeleteDir((PSZ)filename) == NO_ERROR;
1916 /****************************************************************************
1918 Function to get the file time and date for a specific file.
1919 ****************************************************************************/
1920 ibool PMAPI PM_getFileTime(
1921 const char *filename,
1930 if (DosQueryPathInfo((PSZ)filename, FIL_STANDARD, &fs3, sizeof(FILESTATUS3)))
1933 tc.tm_year = fs3.fdateLastWrite.year + 80;
1934 tc.tm_mon = fs3.fdateLastWrite.month - 1;
1935 tc.tm_mday = fs3.fdateLastWrite.day;
1936 tc.tm_hour = fs3.ftimeLastWrite.hours;
1937 tc.tm_min = fs3.ftimeLastWrite.minutes;
1938 tc.tm_sec = fs3.ftimeLastWrite.twosecs * 2;
1939 if((tt = mktime(&tc)) == -1)
1941 if(!(ret = gmtime(&tt)))
1943 time->sec = ret->tm_sec;
1944 time->day = ret->tm_mday;
1945 time->mon = ret->tm_mon + 1;
1946 time->year = ret->tm_year - 80;
1947 time->min = ret->tm_min;
1948 time->hour = ret->tm_hour;
1951 time->sec = fs3.ftimeLastWrite.twosecs * 2;
1952 time->day = fs3.fdateLastWrite.day;
1953 time->mon = fs3.fdateLastWrite.month;
1954 time->year = fs3.fdateLastWrite.year;
1955 time->min = fs3.ftimeLastWrite.minutes;
1956 time->hour = fs3.ftimeLastWrite.hours;
1961 /****************************************************************************
1963 Function to set the file time and date for a specific file.
1964 ****************************************************************************/
1965 ibool PMAPI PM_setFileTime(
1966 const char *filename,
1975 if (DosQueryPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&fs3,sizeof(fs3)))
1978 tc.tm_year = time->year + 80;
1979 tc.tm_mon = time->mon - 1;
1980 tc.tm_mday = time->day;
1981 tc.tm_hour = time->hour;
1982 tc.tm_min = time->min;
1983 tc.tm_sec = time->sec;
1984 if((tt = mktime(&tc)) == -1)
1986 ret = localtime(&tt);
1987 fs3.ftimeLastWrite.twosecs = ret->tm_sec / 2;
1988 fs3.fdateLastWrite.day = ret->tm_mday;
1989 fs3.fdateLastWrite.month = ret->tm_mon + 1;
1990 fs3.fdateLastWrite.year = ret->tm_year - 80;
1991 fs3.ftimeLastWrite.minutes = ret->tm_min;
1992 fs3.ftimeLastWrite.hours = ret->tm_hour;
1995 fs3.ftimeLastWrite.twosecs = time->sec / 2;
1996 fs3.fdateLastWrite.day = time->day;
1997 fs3.fdateLastWrite.month = time->mon;
1998 fs3.fdateLastWrite.year = time->year;
1999 fs3.ftimeLastWrite.minutes = time->min;
2000 fs3.ftimeLastWrite.hours = time->hour;
2002 memcpy(&fs3.fdateLastAccess, &fs3.fdateLastWrite, sizeof(FDATE));
2003 memcpy(&fs3.fdateCreation, &fs3.fdateLastWrite, sizeof(FDATE));
2004 memcpy(&fs3.ftimeLastAccess, &fs3.ftimeLastWrite, sizeof(FTIME));
2005 memcpy(&fs3.ftimeCreation, &fs3.ftimeLastWrite, sizeof(FTIME));
2006 DosSetPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&fs3,sizeof(FILESTATUS3),0L);