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 VDD
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"
37 #include "sdd/sddhelp.h"
42 /*--------------------------- Global variables ----------------------------*/
44 #define MAX_MEMORY_SHARED 100
45 #define MAX_MEMORY_MAPPINGS 100
47 /* TODO: I think the global and linear members will be the same, but not sure yet. */
63 static int numMappings = 0;
64 static memshared shared[MAX_MEMORY_MAPPINGS] = {0};
65 static mmapping maps[MAX_MEMORY_MAPPINGS];
66 ibool _PM_haveBIOS = TRUE;
67 char _PM_cntPath[PM_MAX_PATH] = ""; /* there just isn't any */
68 uchar *_PM_rmBufAddr = NULL;
69 ushort _VARAPI PM_savedDS = 0; /* why can't I use the underscore prefix? */
71 HVDHSEM hevFarCallRet = NULL;
72 HVDHSEM hevIRet = NULL;
73 HHOOK hhookUserReturnHook = NULL;
74 HHOOK hhookUserIRetHook = NULL;
76 static void (PMAPIP fatalErrorCleanup)(void) = NULL;
78 /*----------------------------- Implementation ----------------------------*/
80 /* Functions to read and write CMOS registers */
82 ulong PMAPI _PM_getPDB(void);
83 uchar PMAPI _PM_readCMOS(int index);
84 void PMAPI _PM_writeCMOS(int index,uchar value);
86 VOID HOOKENTRY UserReturnHook(PVOID pRefData, PCRF pcrf);
87 VOID HOOKENTRY UserIRetHook(PVOID pRefData, PCRF pcrf);
89 void PMAPI PM_init(void)
93 /* Initialize VDD-specific data */
94 /* Note: PM_init must be (obviously) called in VDM task context! */
95 VDHCreateSem(&hevFarCallRet, VDH_EVENTSEM);
96 VDHCreateSem(&hevIRet, VDH_EVENTSEM);
97 hhookUserReturnHook = VDHAllocHook(VDH_RETURN_HOOK, (PFNARM)UserReturnHook, 0);
98 hhookUserIRetHook = VDHAllocHook(VDH_RETURN_HOOK, (PFNARM)UserIRetHook, 0);
100 if ((hevIRet == NULL) || (hevFarCallRet == NULL) ||
101 (hhookUserReturnHook == NULL) || (hhookUserIRetHook == NULL)) {
102 /* something failed, we can't go on */
103 /* TODO: take some action here! */
107 /* Do some cleaning up */
108 void PMAPI PM_exit(void)
110 /* Note: Hooks allocated during or after VDM creation are deallocated automatically */
112 VDHDestroySem(hevIRet);
114 if (hevFarCallRet != NULL)
115 VDHDestroySem(hevFarCallRet);
118 ibool PMAPI PM_haveBIOSAccess(void)
119 { return _PM_haveBIOS; }
121 long PMAPI PM_getOSType(void)
122 { return /*_OS_OS2VDD*/ _OS_OS2; } /*FIX!! */
124 int PMAPI PM_getModeType(void)
127 void PMAPI PM_backslash(char *s)
129 uint pos = strlen(s);
130 if (s[pos-1] != '\\') {
136 void PMAPI PM_setFatalErrorCleanup(
137 void (PMAPIP cleanup)(void))
139 fatalErrorCleanup = cleanup;
142 void PMAPI PM_fatalError(const char *msg)
144 if (fatalErrorCleanup)
146 /* Fatal_Error_Handler(msg,0); TODO: implement somehow! */
149 /****************************************************************************
151 len - Place to store the length of the buffer
152 rseg - Place to store the real mode segment of the buffer
153 roff - Place to store the real mode offset of the buffer
156 This function returns the address and length of the global VESA transfer
158 ****************************************************************************/
159 void * PMAPI PM_getVESABuf(
165 *len = 0; /*VESA_BUF_SIZE; */
166 *rseg = (ulong)(_PM_rmBufAddr) >> 4;
167 *roff = (ulong)(_PM_rmBufAddr) & 0xF;
168 return _PM_rmBufAddr;
173 int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out)
179 char * PMAPI PM_getCurrentPath(char *path,int maxLen)
181 strncpy(path, _PM_cntPath, maxLen);
182 path[maxLen - 1] = 0;
186 char PMAPI PM_getBootDrive(void)
189 boot = VDHQuerySysValue(0, VDHGSV_BOOTDRV);
190 return (char)('a' + boot - 1);
193 const char * PMAPI PM_getVBEAFPath(void)
195 static char path[CCHMAXPATH];
197 path[0] = PM_getBootDrive();
201 const char * PMAPI PM_getNucleusPath(void)
203 static char path[CCHMAXPATH];
204 strcpy(path,"x:\\os2\\drivers");
205 path[0] = PM_getBootDrive();
207 strcat(path,"nucleus");
211 const char * PMAPI PM_getNucleusConfigPath(void)
213 static char path[256];
214 strcpy(path,PM_getNucleusPath());
216 strcat(path,"config");
220 const char * PMAPI PM_getUniqueID(void)
221 { return PM_getMachineName(); }
223 const char * PMAPI PM_getMachineName(void)
228 int PMAPI PM_kbhit(void)
231 int PMAPI PM_getch(void)
234 PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen)
240 int PMAPI PM_getConsoleStateSize(void)
246 void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole)
251 void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
256 void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
261 void PMAPI PM_closeConsole(PM_HWND hwndConsole)
266 void PMAPI PM_setOSCursorLocation(int x,int y)
268 uchar *_biosPtr = PM_getBIOSPointer();
269 PM_setByte(_biosPtr+0x50,x);
270 PM_setByte(_biosPtr+0x51,y);
273 void PMAPI PM_setOSScreenWidth(int width,int height)
275 uchar *_biosPtr = PM_getBIOSPointer();
276 PM_setByte(_biosPtr+0x4A,width);
277 PM_setByte(_biosPtr+0x84,height-1);
280 /****************************************************************************
282 Allocate a block of shared memory. For OS/2 VDD we allocate shared memory
283 as locked, global memory that is accessible from any memory context
284 (including interrupt time context), which allows us to load our important
285 data structure and code such that we can access it directly from a ring
287 ****************************************************************************/
288 void * PMAPI PM_mallocShared(long size)
290 ULONG nPages = (size + 0xFFF) >> 12;
293 /* First find a free slot in our shared memory table */
294 for (i = 0; i < MAX_MEMORY_SHARED; i++) {
295 if (shared[i].linear == 0)
298 if (i < MAX_MEMORY_SHARED) {
299 shared[i].linear = VDHAllocPages(NULL, nPages, VDHAP_SYSTEM | VDHAP_FIXED);
300 shared[i].npages = nPages;
301 shared[i].global = (ULONG)shared[i].linear;
302 return (void*)shared[i].global;
307 /****************************************************************************
309 Free a block of shared memory
310 ****************************************************************************/
311 void PMAPI PM_freeShared(void *p)
315 /* Find a shared memory block in our table and free it */
316 for (i = 0; i < MAX_MEMORY_SHARED; i++) {
317 if (shared[i].global == (ulong)p) {
318 VDHFreePages(shared[i].linear);
319 shared[i].linear = 0;
325 void * PMAPI PM_mapToProcess(void *base,ulong limit)
326 { return (void*)base; }
328 ibool PMAPI PM_doBIOSPOST(
334 /* TODO: Figure out how to do this */
338 void * PMAPI PM_getBIOSPointer(void)
339 { return (void*)0x400; }
341 void * PMAPI PM_getA0000Pointer(void)
342 { return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
344 /****************************************************************************
346 base - Physical base address of the memory to maps in
347 limit - Limit of physical memory to region to maps in
350 Linear address of the newly mapped memory.
353 Maps a physical memory range to a linear memory range.
354 ****************************************************************************/
355 ulong MapPhysicalToLinear(
360 ulong linear,length = limit+1;
364 *npages = (length + (base & 0xFFF) + 4095) >> 12;
365 flags = PR_FIXED | PR_STATIC;
366 if (base == 0xA0000) {
367 /* We require the linear address to be aligned to a 64Kb boundary
368 * for mapping the banked framebuffer (so we can do efficient
369 * carry checking for bank changes in the assembler code). The only
370 * way to ensure this is to force the linear address to be aligned
375 if ((linear = (ulong)PageReserve(PR_SYSTEM,*npages,flags)) == (ulong)-1)
377 if (!PageCommitPhys(linear >> 12,*npages,ppage,PC_INCR | PC_USER | PC_WRITEABLE))
380 return linear + (base & 0xFFF);
383 /****************************************************************************
385 base - Physical base address of the memory to map in
386 limit - Limit of physical memory to region to map in
387 isCached - True if the memory should be cached, false if not
390 Linear address of the newly mapped memory.
393 This function maps physical memory to linear memory, which can then be used
394 to create a selector or used directly from 32-bit protected mode programs.
395 This is better than DPMI 0x800, since it allows you to maps physical
396 memory below 1Mb, which gets this memory out of the way of the Windows VxD's
399 NOTE: If the memory is not expected to be cached, this function will
400 directly re-program the PCD (Page Cache Disable) bit in the
401 page tables. There does not appear to be a mechanism in the VMM
402 to control this bit via the regular interface.
403 ****************************************************************************/
404 void * PMAPI PM_mapPhysicalAddr(
409 ulong linear,length = limit+1;
413 /* Search table of existing mappings to see if we have already mapped
414 * a region of memory that will serve this purpose.
416 for (i = 0; i < numMappings; i++) {
417 if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached)
418 return (void*)maps[i].linear;
420 if (numMappings == MAX_MEMORY_MAPPINGS)
423 /* We did not find any previously mapped memory region, so map it in.
424 * Note that we do not use MapPhysToLinear, since this function appears
425 * to have problems mapping memory in the 1Mb physical address space.
426 * Hence we use PageReserve and PageCommitPhys.
428 if ((linear = MapPhysicalToLinear(base,limit,&npages)) == 0)
430 maps[numMappings].physical = base;
431 maps[numMappings].length = length;
432 maps[numMappings].linear = linear;
433 maps[numMappings].npages = npages;
434 maps[numMappings].isCached = isCached;
438 /* Finally disable caching where necessary */
439 if (!isCached && (PDB = _PM_getPDB()) != 0) {
440 int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
441 ulong pageTable,*pPageTable;
444 pPDB = (ulong*)MapPhysicalToLinear(PDB,0xFFF,&npages);
448 startPDB = (linear >> 22) & 0x3FF;
449 startPage = (linear >> 12) & 0x3FF;
450 endPDB = ((linear+limit) >> 22) & 0x3FF;
451 endPage = ((linear+limit) >> 12) & 0x3FF;
452 for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
453 pageTable = pPDB[iPDB] & ~0xFFF;
454 if (pageTable >= 0x100000)
455 pPageTable = (ulong*)MapPhysicalToLinear(pageTable,0xFFF,&npages);
457 pPageTable = (ulong*)pageTable;
458 start = (iPDB == startPDB) ? startPage : 0;
459 end = (iPDB == endPDB) ? endPage : 0x3FF;
460 for (iPage = start; iPage <= end; iPage++)
461 pPageTable[iPage] |= 0x10;
462 PageFree((ulong)pPageTable,PR_STATIC);
464 PageFree((ulong)pPDB,PR_STATIC);
468 return (void*)linear;
471 void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
473 /* We never free the mappings */
476 void PMAPI PM_sleep(ulong milliseconds)
478 /* We never sleep in a VDD */
481 int PMAPI PM_getCOMPort(int port)
483 /* TODO: Re-code this to determine real values using the Plug and Play */
484 /* manager for the OS. */
486 case 0: return 0x3F8;
487 case 1: return 0x2F8;
492 int PMAPI PM_getLPTPort(int port)
494 /* TODO: Re-code this to determine real values using the Plug and Play */
495 /* manager for the OS. */
497 case 0: return 0x3BC;
498 case 1: return 0x378;
499 case 2: return 0x278;
504 ulong PMAPI PM_getPhysicalAddr(void *p)
506 /* TODO: This function should find the physical address of a linear */
511 void PMAPI _PM_freeMemoryMappings(void)
514 /* for (i = 0; i < numMappings; i++) */
515 /* PageFree(maps[i].linear,PR_STATIC); */
518 void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
519 { return (void*)MK_PHYS(r_seg,r_off); }
521 void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
524 void PMAPI PM_freeRealSeg(void *mem)
527 void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
532 /****************************************************************************
534 Load the V86 registers in the client state, and save the original state
535 before loading the registers.
536 ****************************************************************************/
537 static void LoadV86Registers(
542 PCRF pcrf; /* current client register frame */
544 /* get pointer to registers */
545 pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
547 /* Note: We could do VDHPushRegs instead but this should be safer as it */
548 /* doesn't rely on the VDM session having enough free stack space. */
549 *saveRegs = *pcrf; /* save all registers */
551 pcrf->crf_eax = in->e.eax; /* load new values */
552 pcrf->crf_ebx = in->e.ebx;
553 pcrf->crf_ecx = in->e.ecx;
554 pcrf->crf_edx = in->e.edx;
555 pcrf->crf_esi = in->e.esi;
556 pcrf->crf_edi = in->e.edi;
557 pcrf->crf_es = sregs->es;
558 pcrf->crf_ds = sregs->ds;
562 /****************************************************************************
564 Read the V86 registers from the client state and restore the original state.
565 ****************************************************************************/
566 static void ReadV86Registers(
571 PCRF pcrf; /* current client register frame */
573 /* get pointer to registers */
574 pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
576 /* read new register values */
577 out->e.eax = pcrf->crf_eax;
578 out->e.ebx = pcrf->crf_ebx;
579 out->e.ecx = pcrf->crf_ecx;
580 out->e.edx = pcrf->crf_edx;
581 out->e.esi = pcrf->crf_esi;
582 out->e.edi = pcrf->crf_edi;
583 sregs->es = pcrf->crf_es;
584 sregs->ds = pcrf->crf_ds;
586 /* restore original client registers */
590 /****************************************************************************
591 REMARKS: Used for far calls into V86 code
592 ****************************************************************************/
593 VOID HOOKENTRY UserReturnHook(
597 VDHPostEventSem(hevFarCallRet);
600 /****************************************************************************
601 REMARKS: Used for calling BIOS interrupts
602 ****************************************************************************/
603 VOID HOOKENTRY UserIRetHook(
607 VDHPostEventSem(hevIRet);
610 /****************************************************************************
612 Call a V86 real mode function with the specified register values
613 loaded before the call. The call returns with a far ret.
614 Must be called from within a DOS session context!
615 ****************************************************************************/
616 void PMAPI PM_callRealMode(
626 TRACE("SDDHELP: Entering PM_callRealMode()\n");
627 LoadV86Registers(SSToDS(&saveRegs),regs,sregs);
629 /* set up return hook for call */
630 rc = VDHArmReturnHook(hhookUserReturnHook, VDHARH_CSEIP_HOOK);
632 VDHResetEventSem(hevFarCallRet);
634 /* the address is a 16:32 pointer */
635 OFFSETOF32(fnAddress) = off;
636 SEGMENTOF32(fnAddress) = seg;
637 rc = VDHPushFarCall(fnAddress);
640 /* wait until the V86 call returns - our return hook posts the semaphore */
641 rc = VDHWaitEventSem(hevFarCallRet, SEM_INDEFINITE_WAIT);
643 ReadV86Registers(SSToDS(&saveRegs),regs,sregs);
644 TRACE("SDDHELP: Exiting PM_callRealMode()\n");
647 /****************************************************************************
649 Issue a V86 real mode interrupt with the specified register values
650 loaded before the interrupt.
651 Must be called from within a DOS session context!
652 ****************************************************************************/
663 memset(SSToDS(&sregs), 0, sizeof(sregs));
665 #if 0 /* do we need this?? */
666 /* Disable pass-up to our VDD handler so we directly call BIOS */
667 TRACE("SDDHELP: Entering PM_int86()\n");
668 if (disableTSRFlag) {
669 oldDisable = *disableTSRFlag;
674 LoadV86Registers(SSToDS(&saveRegs), in, SSToDS(&sregs));
676 VDHResetEventSem(hevIRet);
677 rc = VDHPushInt(intno);
679 /* set up return hook for interrupt */
680 rc = VDHArmReturnHook(hhookUserIRetHook, VDHARH_NORMAL_IRET);
684 /* wait until the V86 IRETs - our return hook posts the semaphore */
685 rc = VDHWaitEventSem(hevIRet, 5000); /*SEM_INDEFINITE_WAIT); */
687 ReadV86Registers(SSToDS(&saveRegs), out, SSToDS(&sregs));
690 /* Re-enable pass-up to our VDD handler if previously enabled */
692 *disableTSRFlag = oldDisable;
695 TRACE("SDDHELP: Exiting PM_int86()\n");
700 /****************************************************************************
702 Issue a V86 real mode interrupt with the specified register values
703 loaded before the interrupt.
704 ****************************************************************************/
716 /* Disable pass-up to our VxD handler so we directly call BIOS */
717 TRACE("SDDHELP: Entering PM_int86x()\n");
718 if (disableTSRFlag) {
719 oldDisable = *disableTSRFlag;
723 LoadV86Registers(SSToDS(&saveRegs), in, sregs);
725 VDHResetEventSem(hevIRet);
726 rc = VDHPushInt(intno);
728 /* set up return hook for interrupt */
729 rc = VDHArmReturnHook(hhookUserIRetHook, VDHARH_NORMAL_IRET);
733 /* wait until the V86 IRETs - our return hook posts the semaphore */
734 rc = VDHWaitEventSem(hevIRet, 5000); /*SEM_INDEFINITE_WAIT); */
736 ReadV86Registers(SSToDS(&saveRegs), out, sregs);
739 /* Re-enable pass-up to our VxD handler if previously enabled */
741 *disableTSRFlag = oldDisable;
744 TRACE("SDDHELP: Exiting PM_int86x()\n");
748 void PMAPI PM_availableMemory(ulong *physical,ulong *total)
749 { *physical = *total = 0; }
751 /****************************************************************************
753 Allocates a block of locked physical memory.
754 ****************************************************************************/
755 void * PMAPI PM_allocLockedMem(
761 ULONG flags = VDHAP_SYSTEM;
762 ULONG nPages = (size + 0xFFF) >> 12;
764 flags |= (physAddr != NULL) ? VDHAP_PHYSICAL : VDHAP_FIXED;
766 return VDHAllocPages(physAddr, nPages, VDHAP_SYSTEM | VDHAP_PHYSICAL);
769 /****************************************************************************
771 Frees a block of locked physical memory.
772 ****************************************************************************/
773 void PMAPI PM_freeLockedMem(
779 VDHFreePages((PVOID)p);
782 /****************************************************************************
784 Lock linear memory so it won't be paged.
785 ****************************************************************************/
786 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
790 /* TODO: the lock handle is essential for the unlock operation!! */
791 lockHandle = VDHLockMem(p, len, 0, (PVOID)VDHLM_NO_ADDR, NULL);
793 if (lockHandle != NULL)
799 /****************************************************************************
801 Unlock linear memory so it won't be paged.
802 ****************************************************************************/
803 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
805 /* TODO: implement - use a table of lock handles? */
806 /* VDHUnlockPages(lockHandle); */
810 /****************************************************************************
812 Lock linear memory so it won't be paged.
813 ****************************************************************************/
814 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
816 return PM_lockDataPages((void*)p,len,lh);
819 /****************************************************************************
821 Unlock linear memory so it won't be paged.
822 ****************************************************************************/
823 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
825 return PM_unlockDataPages((void*)p,len,lh);
828 /****************************************************************************
830 OS specific shared libraries not supported inside a VDD
831 ****************************************************************************/
832 PM_MODULE PMAPI PM_loadLibrary(
833 const char *szDLLName)
839 /****************************************************************************
841 OS specific shared libraries not supported inside a VDD
842 ****************************************************************************/
843 void * PMAPI PM_getProcAddress(
845 const char *szProcName)
852 /****************************************************************************
854 OS specific shared libraries not supported inside a VDD
855 ****************************************************************************/
856 void PMAPI PM_freeLibrary(
862 /****************************************************************************
864 Function to find the first file matching a search criteria in a directory.
865 ****************************************************************************/
866 void *PMAPI PM_findFirstFile(
867 const char *filename,
868 PM_findData *findData)
870 /* TODO: This function should start a directory enumeration search */
871 /* given the filename (with wildcards). The data should be */
872 /* converted and returned in the findData standard form. */
875 return PM_FILE_INVALID;
878 /****************************************************************************
880 Function to find the next file matching a search criteria in a directory.
881 ****************************************************************************/
882 ibool PMAPI PM_findNextFile(
884 PM_findData *findData)
886 /* TODO: This function should find the next file in directory enumeration */
887 /* search given the search criteria defined in the call to */
888 /* PM_findFirstFile. The data should be converted and returned */
889 /* in the findData standard form. */
895 /****************************************************************************
897 Function to close the find process
898 ****************************************************************************/
899 void PMAPI PM_findClose(
902 /* TODO: This function should close the find process. This may do */
903 /* nothing for some OS'es. */
907 /****************************************************************************
909 Function to determine if a drive is a valid drive or not. Under Unix this
910 function will return false for anything except a value of 3 (considered
911 the root drive, and equivalent to C: for non-Unix systems). The drive
919 ****************************************************************************/
920 ibool PMAPI PM_driveValid(
923 /* Not applicable in a VDD */
928 /****************************************************************************
930 Function to get the current working directory for the specififed drive.
931 Under Unix this will always return the current working directory regardless
932 of what the value of 'drive' is.
933 ****************************************************************************/
934 void PMAPI PM_getdcwd(
939 /* Not applicable in a VDD */
945 /****************************************************************************
947 base - The starting physical base address of the region
948 size - The size in bytes of the region
949 type - Type to place into the MTRR register
952 Error code describing the result.
955 Function to enable write combining for the specified region of memory.
956 ****************************************************************************/
957 int PMAPI PM_enableWriteCombine(
962 return MTRR_enableWriteCombine(base,size,type);
965 /****************************************************************************
967 Function to change the file attributes for a specific file.
968 ****************************************************************************/
969 void PMAPI PM_setFileAttr(
970 const char *filename,
973 /* TODO: Implement this ? */
976 PM_fatalError("PM_setFileAttr not implemented!");
979 /****************************************************************************
981 Function to get the file attributes for a specific file.
982 ****************************************************************************/
983 uint PMAPI PM_getFileAttr(
984 const char *filename)
986 /* TODO: Implement this ? */
988 PM_fatalError("PM_getFileAttr not implemented!");
992 /****************************************************************************
994 Function to create a directory.
995 ****************************************************************************/
996 ibool PMAPI PM_mkdir(
997 const char *filename)
999 /* TODO: Implement this ? */
1001 PM_fatalError("PM_mkdir not implemented!");
1005 /****************************************************************************
1007 Function to remove a directory.
1008 ****************************************************************************/
1009 ibool PMAPI PM_rmdir(
1010 const char *filename)
1012 /* TODO: Implement this ? */
1014 PM_fatalError("PM_rmdir not implemented!");
1018 /****************************************************************************
1020 Function to get the file time and date for a specific file.
1021 ****************************************************************************/
1022 ibool PMAPI PM_getFileTime(
1023 const char *filename,
1027 /* TODO: Implement this ? */
1031 PM_fatalError("PM_getFileTime not implemented!");
1035 /****************************************************************************
1037 Function to set the file time and date for a specific file.
1038 ****************************************************************************/
1039 ibool PMAPI PM_setFileTime(
1040 const char *filename,
1044 /* TODO: Implement this ? */
1048 PM_fatalError("PM_setFileTime not implemented!");