Coding style cleanup
[platform/kernel/u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / win32 / pm.c
1 /****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
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
11 *
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.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  Win32
26 *
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.
32 *
33 ****************************************************************************/
34
35 #define WIN32_LEAN_AND_MEAN
36 #define STRICT
37 #include <windows.h>
38 #include <mmsystem.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <direct.h>
43 #include "pmapi.h"
44 #include "drvlib/os/os.h"
45 #include "pm_help.h"
46
47 /*--------------------------- Global variables ----------------------------*/
48
49 ibool           _PM_haveWinNT;      /* True if we are running on NT     */
50 static uint     VESABuf_len = 1024; /* Length of the VESABuf buffer     */
51 static void     *VESABuf_ptr = NULL;/* Near pointer to VESABuf          */
52 static uint     VESABuf_rseg;       /* Real mode segment of VESABuf     */
53 static uint     VESABuf_roff;       /* Real mode offset of VESABuf      */
54 HANDLE          _PM_hDevice = NULL; /* Handle to Win32 VxD              */
55 static ibool    inited = false;     /* Flags if we are initialised      */
56 static void     (PMAPIP fatalErrorCleanup)(void) = NULL;
57
58 static char *szMachineNameKey   = "System\\CurrentControlSet\\control\\ComputerName\\ComputerName";
59 static char *szMachineNameKeyNT = "System\\CurrentControlSet\\control\\ComputerName\\ActiveComputerName";
60 static char *szMachineName      = "ComputerName";
61
62 /*----------------------------- Implementation ----------------------------*/
63
64 /* Macro to check for a valid, loaded version of PMHELP. We check this
65  * on demand when we need these services rather than when PM_init() is
66  * called because if we are running on DirectDraw we don't need PMHELP.VXD.
67  */
68
69 #define CHECK_FOR_PMHELP()                                                  \
70 {                                                                           \
71     if (_PM_hDevice == INVALID_HANDLE_VALUE)                                \
72         if (_PM_haveWinNT)                                                  \
73             PM_fatalError("Unable to connect to PMHELP.SYS or SDDHELP.SYS!"); \
74         else                                                                  \
75             PM_fatalError("Unable to connect to PMHELP.VXD or SDDHELP.VXD!"); \
76 }
77
78 /****************************************************************************
79 REMARKS:
80 Initialise the PM library and connect to our helper device driver. If we
81 cannot connect to our helper device driver, we bail out with an error
82 message. Our Windows 9x VxD is dynamically loadable, so it can be loaded
83 after the system has started.
84 ****************************************************************************/
85 void PMAPI PM_init(void)
86 {
87     DWORD   inBuf[1];   /* Buffer to receive data from VxD  */
88     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
89     DWORD   count;      /* Count of bytes returned from VxD */
90     char    cntPath[PM_MAX_PATH];
91     char    *env;
92
93     /* Create a file handle for the static VxD if possible, otherwise
94      * dynamically load the PMHELP helper VxD. Note that if an old version
95      * of SDD is loaded, we use the PMHELP VxD instead.
96      */
97     if (!inited) {
98         /* Determine if we are running under Windows NT or not and
99          * set the global OS type variable.
100          */
101         _PM_haveWinNT = false;
102         if ((GetVersion() & 0x80000000UL) == 0)
103             _PM_haveWinNT = true;
104         ___drv_os_type = (_PM_haveWinNT) ? _OS_WINNT : _OS_WIN95;
105
106         /* Now try to connect to SDDHELP.VXD or SDDHELP.SYS */
107         _PM_hDevice = CreateFile(SDDHELP_MODULE_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
108         if (_PM_hDevice != INVALID_HANDLE_VALUE) {
109             if (!DeviceIoControl(_PM_hDevice, PMHELP_GETVER32, NULL, 0,
110                     outBuf, sizeof(outBuf), &count, NULL) || outBuf[0] < PMHELP_VERSION) {
111                 /* Old version of SDDHELP loaded, so use PMHELP instead */
112                 CloseHandle(_PM_hDevice);
113                 _PM_hDevice = INVALID_HANDLE_VALUE;
114                 }
115             }
116         if (_PM_hDevice == INVALID_HANDLE_VALUE) {
117             /* First try to see if there is a currently loaded PMHELP driver.
118              * This is usually the case when we are running under Windows NT/2K.
119              */
120             _PM_hDevice = CreateFile(PMHELP_MODULE_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
121             if (_PM_hDevice == INVALID_HANDLE_VALUE) {
122                 /* The driver was not staticly loaded, so try creating a file handle
123                  * to a dynamic version of the VxD if possible. Note that on WinNT/2K we
124                  * cannot support dynamically loading the drivers.
125                  */
126                 _PM_hDevice = CreateFile(PMHELP_VXD_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
127                 }
128             }
129         if (_PM_hDevice != INVALID_HANDLE_VALUE) {
130             /* Call the driver to determine the version number */
131             if (!DeviceIoControl(_PM_hDevice, PMHELP_GETVER32, inBuf, sizeof(inBuf),
132                     outBuf, sizeof(outBuf), &count, NULL) || outBuf[0] < PMHELP_VERSION) {
133                 if (_PM_haveWinNT)
134                     PM_fatalError("Older version of PMHELP.SYS found!");
135                 else
136                     PM_fatalError("Older version of PMHELP.VXD found!");
137                 }
138
139             /* Now set the current path inside the VxD so it knows what the
140              * current directory is for loading Nucleus drivers.
141              */
142             inBuf[0] = (ulong)PM_getCurrentPath(cntPath,sizeof(cntPath));
143             if (!DeviceIoControl(_PM_hDevice, PMHELP_SETCNTPATH32, inBuf, sizeof(inBuf), outBuf, sizeof(outBuf), &count, NULL))
144                 PM_fatalError("Unable to set VxD current path!");
145
146             /* Now pass down the NUCLEUS_PATH environment variable to the device
147              * driver so it can use this value if it is found.
148              */
149             if ((env = getenv("NUCLEUS_PATH")) != NULL) {
150                 inBuf[0] = (ulong)env;
151                 if (!DeviceIoControl(_PM_hDevice, PMHELP_SETNUCLEUSPATH32, inBuf, sizeof(inBuf), outBuf, sizeof(outBuf), &count, NULL))
152                     PM_fatalError("Unable to set VxD Nucleus path!");
153                 }
154
155             /* Enable IOPL for ring-3 code by default if driver is present */
156             if (_PM_haveWinNT)
157                 PM_setIOPL(3);
158             }
159
160         /* Indicate that we have been initialised */
161         inited = true;
162         }
163 }
164
165 /****************************************************************************
166 REMARKS:
167 We do have BIOS access under Windows 9x, but not under Windows NT.
168 ****************************************************************************/
169 int PMAPI PM_setIOPL(
170     int iopl)
171 {
172     DWORD       inBuf[1];   /* Buffer to receive data from VxD  */
173     DWORD       outBuf[1];  /* Buffer to receive data from VxD  */
174     DWORD       count;      /* Count of bytes returned from VxD */
175     static int  cntIOPL = 0;
176     int         oldIOPL = cntIOPL;
177
178     /* Enable I/O by adjusting the I/O permissions map on Windows NT */
179     if (_PM_haveWinNT) {
180         CHECK_FOR_PMHELP();
181         if (iopl == 3)
182             DeviceIoControl(_PM_hDevice, PMHELP_ENABLERING3IOPL, inBuf, sizeof(inBuf),outBuf, sizeof(outBuf), &count, NULL);
183         else
184             DeviceIoControl(_PM_hDevice, PMHELP_DISABLERING3IOPL, inBuf, sizeof(inBuf),outBuf, sizeof(outBuf), &count, NULL);
185         cntIOPL = iopl;
186         return oldIOPL;
187         }
188
189     /* We always have IOPL on Windows 9x */
190     return 3;
191 }
192
193 /****************************************************************************
194 REMARKS:
195 We do have BIOS access under Windows 9x, but not under Windows NT.
196 ****************************************************************************/
197 ibool PMAPI PM_haveBIOSAccess(void)
198 {
199     if (PM_getOSType() == _OS_WINNT)
200         return false;
201     else
202         return _PM_hDevice != INVALID_HANDLE_VALUE;
203 }
204
205 /****************************************************************************
206 REMARKS:
207 Return the operating system type identifier.
208 ****************************************************************************/
209 long PMAPI PM_getOSType(void)
210 {
211     if ((GetVersion() & 0x80000000UL) == 0)
212         return ___drv_os_type = _OS_WINNT;
213     else
214         return ___drv_os_type = _OS_WIN95;
215 }
216
217 /****************************************************************************
218 REMARKS:
219 Return the runtime type identifier.
220 ****************************************************************************/
221 int PMAPI PM_getModeType(void)
222 {
223     return PM_386;
224 }
225
226 /****************************************************************************
227 REMARKS:
228 Add a file directory separator to the end of the filename.
229 ****************************************************************************/
230 void PMAPI PM_backslash(
231     char *s)
232 {
233     uint pos = strlen(s);
234     if (s[pos-1] != '\\') {
235         s[pos] = '\\';
236         s[pos+1] = '\0';
237         }
238 }
239
240 /****************************************************************************
241 REMARKS:
242 Add a user defined PM_fatalError cleanup function.
243 ****************************************************************************/
244 void PMAPI PM_setFatalErrorCleanup(
245     void (PMAPIP cleanup)(void))
246 {
247     fatalErrorCleanup = cleanup;
248 }
249
250 /****************************************************************************
251 REMARKS:
252 Report a fatal error condition and halt the program.
253 ****************************************************************************/
254 void PMAPI PM_fatalError(
255     const char *msg)
256 {
257     if (fatalErrorCleanup)
258         fatalErrorCleanup();
259     MessageBox(NULL,msg,"Fatal Error!", MB_ICONEXCLAMATION);
260     exit(1);
261 }
262
263 /****************************************************************************
264 REMARKS:
265 Allocate the real mode VESA transfer buffer for communicating with the BIOS.
266 ****************************************************************************/
267 void * PMAPI PM_getVESABuf(
268     uint *len,
269     uint *rseg,
270     uint *roff)
271 {
272     DWORD   outBuf[4];  /* Buffer to receive data from VxD  */
273     DWORD   count;      /* Count of bytes returned from VxD */
274
275     /* We require the helper VxD to be loaded staticly in order to support
276      * the VESA transfer buffer. We do not support dynamically allocating
277      * real mode memory buffers from Win32 programs (we need a 16-bit DLL
278      * for this, and Windows 9x becomes very unstable if you free the
279      * memory blocks out of order).
280      */
281     if (!inited)
282         PM_init();
283     if (!VESABuf_ptr) {
284         CHECK_FOR_PMHELP();
285         if (DeviceIoControl(_PM_hDevice, PMHELP_GETVESABUF32, NULL, 0,
286                 outBuf, sizeof(outBuf), &count, NULL)) {
287             if (!outBuf[0])
288                 return NULL;
289             VESABuf_ptr = (void*)outBuf[0];
290             VESABuf_len = outBuf[1];
291             VESABuf_rseg = outBuf[2];
292             VESABuf_roff = outBuf[3];
293             }
294         }
295     *len = VESABuf_len;
296     *rseg = VESABuf_rseg;
297     *roff = VESABuf_roff;
298     return VESABuf_ptr;
299 }
300
301 /****************************************************************************
302 REMARKS:
303 Check if a key has been pressed.
304 ****************************************************************************/
305 int PMAPI PM_kbhit(void)
306 {
307     /* Not used in Windows */
308     return true;
309 }
310
311 /****************************************************************************
312 REMARKS:
313 Wait for and return the next keypress.
314 ****************************************************************************/
315 int PMAPI PM_getch(void)
316 {
317     /* Not used in Windows */
318     return 0xD;
319 }
320
321 /****************************************************************************
322 REMARKS:
323 Set the location of the OS console cursor.
324 ****************************************************************************/
325 void PM_setOSCursorLocation(
326     int x,
327     int y)
328 {
329     /* Nothing to do for Windows */
330     (void)x;
331     (void)y;
332 }
333
334 /****************************************************************************
335 REMARKS:
336 Set the width of the OS console.
337 ****************************************************************************/
338 void PM_setOSScreenWidth(
339     int width,
340     int height)
341 {
342     /* Nothing to do for Windows */
343     (void)width;
344     (void)height;
345 }
346
347 /****************************************************************************
348 REMARKS:
349 Set the real time clock handler (used for software stereo modes).
350 ****************************************************************************/
351 ibool PMAPI PM_setRealTimeClockHandler(
352     PM_intHandler ih,
353     int frequency)
354 {
355     /* We do not support this from Win32 programs. Rather the VxD handles
356      * this stuff it will take care of hooking the stereo flip functions at
357      * the VxD level.
358      */
359     (void)ih;
360     (void)frequency;
361     return false;
362 }
363
364 /****************************************************************************
365 REMARKS:
366 Set the real time clock frequency (for stereo modes).
367 ****************************************************************************/
368 void PMAPI PM_setRealTimeClockFrequency(
369     int frequency)
370 {
371     /* Not supported under Win32 */
372     (void)frequency;
373 }
374
375 /****************************************************************************
376 REMARKS:
377 Restore the original real time clock handler.
378 ****************************************************************************/
379 void PMAPI PM_restoreRealTimeClockHandler(void)
380 {
381     /* Not supported under Win32 */
382 }
383
384 /****************************************************************************
385 REMARKS:
386 Return the current operating system path or working directory.
387 ****************************************************************************/
388 char * PMAPI PM_getCurrentPath(
389     char *path,
390     int maxLen)
391 {
392     return getcwd(path,maxLen);
393 }
394
395 /****************************************************************************
396 REMARKS:
397 Query a string from the registry (extended version).
398 ****************************************************************************/
399 static ibool REG_queryStringEx(
400     HKEY hKey,
401     const char *szValue,
402     char *value,
403     ulong size)
404 {
405     DWORD   type;
406
407     if (RegQueryValueEx(hKey,(PCHAR)szValue,(PDWORD)NULL,(PDWORD)&type,(LPBYTE)value,(PDWORD)&size) == ERROR_SUCCESS)
408         return true;
409     return false;
410 }
411
412 /****************************************************************************
413 REMARKS:
414 Query a string from the registry.
415 ****************************************************************************/
416 static ibool REG_queryString(
417     const char *szKey,
418     const char *szValue,
419     char *value,
420     DWORD size)
421 {
422     HKEY    hKey;
423     ibool   status = false;
424
425     memset(value,0,sizeof(value));
426     if (RegOpenKey(HKEY_LOCAL_MACHINE,szKey,&hKey) == ERROR_SUCCESS) {
427         status = REG_queryStringEx(hKey,szValue,value,size);
428         RegCloseKey(hKey);
429         }
430     return status;
431 }
432
433 /****************************************************************************
434 REMARKS:
435 Return the drive letter for the boot drive.
436 ****************************************************************************/
437 char PMAPI PM_getBootDrive(void)
438 {
439     static char path[256];
440     GetSystemDirectory(path,sizeof(path));
441     return path[0];
442 }
443
444 /****************************************************************************
445 REMARKS:
446 Return the path to the VBE/AF driver files.
447 ****************************************************************************/
448 const char * PMAPI PM_getVBEAFPath(void)
449 {
450     return "c:\\";
451 }
452
453 /****************************************************************************
454 REMARKS:
455 Return the path to the Nucleus driver files.
456 ****************************************************************************/
457 const char * PMAPI PM_getNucleusPath(void)
458 {
459     static char path[256];
460     char        *env;
461
462     if ((env = getenv("NUCLEUS_PATH")) != NULL)
463         return env;
464     GetSystemDirectory(path,sizeof(path));
465     strcat(path,"\\nucleus");
466     return path;
467 }
468
469 /****************************************************************************
470 REMARKS:
471 Return the path to the Nucleus configuration files.
472 ****************************************************************************/
473 const char * PMAPI PM_getNucleusConfigPath(void)
474 {
475     static char path[256];
476     strcpy(path,PM_getNucleusPath());
477     PM_backslash(path);
478     strcat(path,"config");
479     return path;
480 }
481
482 /****************************************************************************
483 REMARKS:
484 Return a unique identifier for the machine if possible.
485 ****************************************************************************/
486 const char * PMAPI PM_getUniqueID(void)
487 {
488     return PM_getMachineName();
489 }
490
491 /****************************************************************************
492 REMARKS:
493 Get the name of the machine on the network.
494 ****************************************************************************/
495 const char * PMAPI PM_getMachineName(void)
496 {
497     static char name[256];
498
499     if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name)))
500         return name;
501     if (REG_queryString(szMachineNameKeyNT,szMachineName,name,sizeof(name)))
502         return name;
503     return "Unknown";
504 }
505
506 /****************************************************************************
507 REMARKS:
508 Return a pointer to the real mode BIOS data area.
509 ****************************************************************************/
510 void * PMAPI PM_getBIOSPointer(void)
511 {
512     if (_PM_haveWinNT) {
513         /* On Windows NT we have to map it physically directly */
514             return PM_mapPhysicalAddr(0x400, 0x1000, true);
515         }
516     else {
517         /* For Windows 9x we can access this memory directly */
518         return (void*)0x400;
519         }
520 }
521
522 /****************************************************************************
523 REMARKS:
524 Return a pointer to 0xA0000 physical VGA graphics framebuffer.
525 ****************************************************************************/
526 void * PMAPI PM_getA0000Pointer(void)
527 {
528     if (_PM_haveWinNT) {
529         /* On Windows NT we have to map it physically directly */
530             return PM_mapPhysicalAddr(0xA0000, 0x0FFFF, false);
531         }
532     else {
533         /* Always use the 0xA0000 linear address so that we will use
534          * whatever page table mappings are set up for us (ie: for virtual
535          * bank switching.
536          */
537         return (void*)0xA0000;
538         }
539 }
540
541 /****************************************************************************
542 REMARKS:
543 Map a physical address to a linear address in the callers process.
544 ****************************************************************************/
545 void * PMAPI PM_mapPhysicalAddr(
546     ulong base,
547     ulong limit,
548     ibool isCached)
549 {
550     DWORD   inBuf[3];   /* Buffer to send data to VxD       */
551     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
552     DWORD   count;      /* Count of bytes returned from VxD */
553
554     if (!inited)
555         PM_init();
556     inBuf[0] = base;
557     inBuf[1] = limit;
558     inBuf[2] = isCached;
559     CHECK_FOR_PMHELP();
560     if (DeviceIoControl(_PM_hDevice, PMHELP_MAPPHYS32, inBuf, sizeof(inBuf),
561             outBuf, sizeof(outBuf), &count, NULL))
562         return (void*)outBuf[0];
563     return NULL;
564 }
565
566 /****************************************************************************
567 REMARKS:
568 Free a physical address mapping allocated by PM_mapPhysicalAddr.
569 ****************************************************************************/
570 void PMAPI PM_freePhysicalAddr(
571     void *ptr,
572     ulong limit)
573 {
574     /* We never free the mappings under Win32 (the VxD tracks them and
575      * reissues the same mappings until the system is rebooted).
576      */
577     (void)ptr;
578     (void)limit;
579 }
580
581 /****************************************************************************
582 REMARKS:
583 Find the physical address of a linear memory address in current process.
584 ****************************************************************************/
585 ulong PMAPI PM_getPhysicalAddr(
586     void *p)
587 {
588     DWORD   inBuf[1];   /* Buffer to send data to VxD       */
589     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
590     DWORD   count;      /* Count of bytes returned from VxD */
591
592     if (!inited)
593         PM_init();
594     inBuf[0] = (ulong)p;
595     CHECK_FOR_PMHELP();
596     if (DeviceIoControl(_PM_hDevice, PMHELP_GETPHYSICALADDR32, inBuf, sizeof(inBuf),
597             outBuf, sizeof(outBuf), &count, NULL))
598         return outBuf[0];
599     return 0xFFFFFFFFUL;
600 }
601
602 /****************************************************************************
603 REMARKS:
604 Find the physical address of a linear memory address in current process.
605 ****************************************************************************/
606 ibool PMAPI PM_getPhysicalAddrRange(
607     void *p,
608     ulong length,
609     ulong *physAddress)
610 {
611     DWORD   inBuf[3];   /* Buffer to send data to VxD       */
612     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
613     DWORD   count;      /* Count of bytes returned from VxD */
614
615     if (!inited)
616         PM_init();
617     inBuf[0] = (ulong)p;
618     inBuf[1] = (ulong)length;
619     inBuf[2] = (ulong)physAddress;
620     CHECK_FOR_PMHELP();
621     if (DeviceIoControl(_PM_hDevice, PMHELP_GETPHYSICALADDRRANGE32, inBuf, sizeof(inBuf),
622             outBuf, sizeof(outBuf), &count, NULL))
623         return outBuf[0];
624     return false;
625 }
626
627 /****************************************************************************
628 REMARKS:
629 Sleep for the specified number of milliseconds.
630 ****************************************************************************/
631 void PMAPI PM_sleep(
632     ulong milliseconds)
633 {
634     Sleep(milliseconds);
635 }
636
637 /****************************************************************************
638 REMARKS:
639 Return the base I/O port for the specified COM port.
640 ****************************************************************************/
641 int PMAPI PM_getCOMPort(int port)
642 {
643     /* TODO: Re-code this to determine real values using the Plug and Play */
644     /*       manager for the OS. */
645     switch (port) {
646         case 0: return 0x3F8;
647         case 1: return 0x2F8;
648         case 2: return 0x3E8;
649         case 3: return 0x2E8;
650         }
651     return 0;
652 }
653
654 /****************************************************************************
655 REMARKS:
656 Return the base I/O port for the specified LPT port.
657 ****************************************************************************/
658 int PMAPI PM_getLPTPort(int port)
659 {
660     /* TODO: Re-code this to determine real values using the Plug and Play */
661     /*       manager for the OS. */
662     switch (port) {
663         case 0: return 0x3BC;
664         case 1: return 0x378;
665         case 2: return 0x278;
666         }
667     return 0;
668 }
669
670 /****************************************************************************
671 REMARKS:
672 Allocate a block of shared memory. For Win9x we allocate shared memory
673 as locked, global memory that is accessible from any memory context
674 (including interrupt time context), which allows us to load our important
675 data structure and code such that we can access it directly from a ring
676 0 interrupt context.
677 ****************************************************************************/
678 void * PMAPI PM_mallocShared(
679     long size)
680 {
681     DWORD   inBuf[1];   /* Buffer to send data to VxD       */
682     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
683     DWORD   count;      /* Count of bytes returned from VxD */
684
685     inBuf[0] = size;
686     CHECK_FOR_PMHELP();
687     if (DeviceIoControl(_PM_hDevice, PMHELP_MALLOCSHARED32, inBuf, sizeof(inBuf),
688             outBuf, sizeof(outBuf), &count, NULL))
689         return (void*)outBuf[0];
690     return NULL;
691 }
692
693 /****************************************************************************
694 REMARKS:
695 Free a block of shared memory.
696 ****************************************************************************/
697 void PMAPI PM_freeShared(
698     void *ptr)
699 {
700     DWORD   inBuf[1];   /* Buffer to send data to VxD       */
701
702     inBuf[0] = (ulong)ptr;
703     CHECK_FOR_PMHELP();
704     DeviceIoControl(_PM_hDevice, PMHELP_FREESHARED32, inBuf, sizeof(inBuf), NULL, 0, NULL, NULL);
705 }
706
707 /****************************************************************************
708 REMARKS:
709 Map a linear memory address to the calling process address space. The
710 address will have been allocated in another process using the
711 PM_mapPhysicalAddr function.
712 ****************************************************************************/
713 void * PMAPI PM_mapToProcess(
714     void *base,
715     ulong limit)
716 {
717     (void)base;
718     (void)limit;
719     return base;
720 }
721
722 /****************************************************************************
723 REMARKS:
724 Map a real mode pointer to a protected mode pointer.
725 ****************************************************************************/
726 void * PMAPI PM_mapRealPointer(
727     uint r_seg,
728     uint r_off)
729 {
730     return (void*)(MK_PHYS(r_seg,r_off));
731 }
732
733 /****************************************************************************
734 REMARKS:
735 Allocate a block of real mode memory
736 ****************************************************************************/
737 void * PMAPI PM_allocRealSeg(
738     uint size,
739     uint *r_seg,
740     uint *r_off)
741 {
742     /* We do not support dynamically allocating real mode memory buffers
743      * from Win32 programs (we need a 16-bit DLL for this, and Windows
744      * 9x becomes very unstable if you free the memory blocks out of order).
745      */
746     (void)size;
747     (void)r_seg;
748     (void)r_off;
749     return NULL;
750 }
751
752 /****************************************************************************
753 REMARKS:
754 Free a block of real mode memory.
755 ****************************************************************************/
756 void PMAPI PM_freeRealSeg(
757     void *mem)
758 {
759     /* Not supported in Windows */
760     (void)mem;
761 }
762
763 /****************************************************************************
764 REMARKS:
765 Issue a real mode interrupt (parameters in DPMI compatible structure)
766 ****************************************************************************/
767 void PMAPI DPMI_int86(
768     int intno,
769     DPMI_regs *regs)
770 {
771     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
772     DWORD   count;      /* Count of bytes returned from VxD */
773
774     if (!inited)
775         PM_init();
776     inBuf[0] = intno;
777     inBuf[1] = (ulong)regs;
778     CHECK_FOR_PMHELP();
779     DeviceIoControl(_PM_hDevice, PMHELP_DPMIINT8632, inBuf, sizeof(inBuf),
780         NULL, 0, &count, NULL);
781 }
782
783 /****************************************************************************
784 REMARKS:
785 Issue a real mode interrupt.
786 ****************************************************************************/
787 int PMAPI PM_int86(
788     int intno,
789     RMREGS *in,
790     RMREGS *out)
791 {
792     DWORD   inBuf[3];   /* Buffer to send data to VxD       */
793     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
794     DWORD   count;      /* Count of bytes returned from VxD */
795
796     if (!inited)
797         PM_init();
798     inBuf[0] = intno;
799     inBuf[1] = (ulong)in;
800     inBuf[2] = (ulong)out;
801     CHECK_FOR_PMHELP();
802     if (DeviceIoControl(_PM_hDevice, PMHELP_INT8632, inBuf, sizeof(inBuf),
803             outBuf, sizeof(outBuf), &count, NULL))
804         return outBuf[0];
805     return 0;
806 }
807
808 /****************************************************************************
809 REMARKS:
810 Issue a real mode interrupt.
811 ****************************************************************************/
812 int PMAPI PM_int86x(
813     int intno,
814     RMREGS *in,
815     RMREGS *out,
816     RMSREGS *sregs)
817 {
818     DWORD   inBuf[4];   /* Buffer to send data to VxD       */
819     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
820     DWORD   count;      /* Count of bytes returned from VxD */
821
822     if (!inited)
823         PM_init();
824     inBuf[0] = intno;
825     inBuf[1] = (ulong)in;
826     inBuf[2] = (ulong)out;
827     inBuf[3] = (ulong)sregs;
828     CHECK_FOR_PMHELP();
829     if (DeviceIoControl(_PM_hDevice, PMHELP_INT86X32, inBuf, sizeof(inBuf),
830             outBuf, sizeof(outBuf), &count, NULL))
831         return outBuf[0];
832     return 0;
833 }
834
835 /****************************************************************************
836 REMARKS:
837 Call a real mode far function.
838 ****************************************************************************/
839 void PMAPI PM_callRealMode(
840     uint seg,
841     uint off,
842     RMREGS *in,
843     RMSREGS *sregs)
844 {
845     DWORD   inBuf[4];   /* Buffer to send data to VxD       */
846     DWORD   count;      /* Count of bytes returned from VxD */
847
848     if (!inited)
849         PM_init();
850     inBuf[0] = seg;
851     inBuf[1] = off;
852     inBuf[2] = (ulong)in;
853     inBuf[3] = (ulong)sregs;
854     CHECK_FOR_PMHELP();
855     DeviceIoControl(_PM_hDevice, PMHELP_CALLREALMODE32, inBuf, sizeof(inBuf),
856         NULL, 0, &count, NULL);
857 }
858
859 /****************************************************************************
860 REMARKS:
861 Return the amount of available memory.
862 ****************************************************************************/
863 void PMAPI PM_availableMemory(
864     ulong *physical,
865     ulong *total)
866 {
867     /* We don't support this under Win32 at the moment */
868     *physical = *total = 0;
869 }
870
871 /****************************************************************************
872 REMARKS:
873 Allocate a block of locked, physical memory for DMA operations.
874 ****************************************************************************/
875 void * PMAPI PM_allocLockedMem(
876     uint size,
877     ulong *physAddr,
878     ibool contiguous,
879     ibool below16M)
880 {
881     DWORD   inBuf[4];   /* Buffer to send data to VxD       */
882     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
883     DWORD   count;      /* Count of bytes returned from VxD */
884
885     if (!inited)
886         PM_init();
887     inBuf[0] = size;
888     inBuf[1] = (ulong)physAddr;
889     inBuf[2] = (ulong)contiguous;
890     inBuf[3] = (ulong)below16M;
891     CHECK_FOR_PMHELP();
892     if (DeviceIoControl(_PM_hDevice, PMHELP_ALLOCLOCKED32, inBuf, sizeof(inBuf),
893             outBuf, sizeof(outBuf), &count, NULL))
894         return (void*)outBuf[0];
895     return NULL;
896 }
897
898 /****************************************************************************
899 REMARKS:
900 Free a block of locked physical memory.
901 ****************************************************************************/
902 void PMAPI PM_freeLockedMem(
903     void *p,
904     uint size,
905     ibool contiguous)
906 {
907     DWORD   inBuf[3];   /* Buffer to send data to VxD       */
908     DWORD   count;      /* Count of bytes returned from VxD */
909
910     if (!inited)
911         PM_init();
912     inBuf[0] = (ulong)p;
913     inBuf[1] = size;
914     inBuf[2] = contiguous;
915     CHECK_FOR_PMHELP();
916     DeviceIoControl(_PM_hDevice, PMHELP_FREELOCKED32, inBuf, sizeof(inBuf),
917         NULL, 0, &count, NULL);
918 }
919
920 /****************************************************************************
921 REMARKS:
922 Allocates a page aligned and page sized block of memory
923 ****************************************************************************/
924 void * PMAPI PM_allocPage(
925     ibool locked)
926 {
927     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
928     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
929     DWORD   count;      /* Count of bytes returned from VxD */
930
931     if (!inited)
932         PM_init();
933     inBuf[0] = locked;
934     CHECK_FOR_PMHELP();
935     if (DeviceIoControl(_PM_hDevice, PMHELP_ALLOCPAGE32, inBuf, sizeof(inBuf),
936             outBuf, sizeof(outBuf), &count, NULL))
937         return (void*)outBuf[0];
938     return NULL;
939 }
940
941 /****************************************************************************
942 REMARKS:
943 Free a page aligned and page sized block of memory
944 ****************************************************************************/
945 void PMAPI PM_freePage(
946     void *p)
947 {
948     DWORD   inBuf[1];   /* Buffer to send data to VxD       */
949     DWORD   count;      /* Count of bytes returned from VxD */
950
951     if (!inited)
952         PM_init();
953     inBuf[0] = (ulong)p;
954     CHECK_FOR_PMHELP();
955     DeviceIoControl(_PM_hDevice, PMHELP_FREEPAGE32, inBuf, sizeof(inBuf),
956         NULL, 0, &count, NULL);
957 }
958
959 /****************************************************************************
960 REMARKS:
961 Lock linear memory so it won't be paged.
962 ****************************************************************************/
963 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
964 {
965     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
966     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
967     DWORD   count;      /* Count of bytes returned from VxD */
968
969     inBuf[0] = (ulong)p;
970     inBuf[1] = len;
971     inBuf[2] = (ulong)lh;
972     CHECK_FOR_PMHELP();
973     if (DeviceIoControl(_PM_hDevice, PMHELP_LOCKDATAPAGES32, inBuf, sizeof(inBuf),
974             outBuf, sizeof(outBuf), &count, NULL))
975         return outBuf[0];
976     return 0;
977 }
978
979 /****************************************************************************
980 REMARKS:
981 Unlock linear memory so it won't be paged.
982 ****************************************************************************/
983 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
984 {
985     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
986     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
987     DWORD   count;      /* Count of bytes returned from VxD */
988
989     inBuf[0] = (ulong)p;
990     inBuf[1] = len;
991     inBuf[2] = (ulong)lh;
992     CHECK_FOR_PMHELP();
993     if (DeviceIoControl(_PM_hDevice, PMHELP_UNLOCKDATAPAGES32, inBuf, sizeof(inBuf),
994             outBuf, sizeof(outBuf), &count, NULL))
995         return outBuf[0];
996     return 0;
997 }
998
999 /****************************************************************************
1000 REMARKS:
1001 Lock linear memory so it won't be paged.
1002 ****************************************************************************/
1003 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1004 {
1005     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
1006     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
1007     DWORD   count;      /* Count of bytes returned from VxD */
1008
1009     inBuf[0] = (ulong)p;
1010     inBuf[1] = len;
1011     inBuf[2] = (ulong)lh;
1012     CHECK_FOR_PMHELP();
1013     if (DeviceIoControl(_PM_hDevice, PMHELP_LOCKCODEPAGES32, inBuf, sizeof(inBuf),
1014             outBuf, sizeof(outBuf), &count, NULL))
1015         return outBuf[0];
1016     return 0;
1017 }
1018
1019 /****************************************************************************
1020 REMARKS:
1021 Unlock linear memory so it won't be paged.
1022 ****************************************************************************/
1023 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1024 {
1025     DWORD   inBuf[2];   /* Buffer to send data to VxD       */
1026     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
1027     DWORD   count;      /* Count of bytes returned from VxD */
1028
1029     inBuf[0] = (ulong)p;
1030     inBuf[1] = len;
1031     inBuf[2] = (ulong)lh;
1032     CHECK_FOR_PMHELP();
1033     if (DeviceIoControl(_PM_hDevice, PMHELP_UNLOCKCODEPAGES32, inBuf, sizeof(inBuf),
1034             outBuf, sizeof(outBuf), &count, NULL))
1035         return outBuf[0];
1036     return 0;
1037 }
1038
1039 /****************************************************************************
1040 REMARKS:
1041 Call the VBE/Core software interrupt to change display banks.
1042 ****************************************************************************/
1043 void PMAPI PM_setBankA(
1044     int bank)
1045 {
1046     RMREGS  regs;
1047     regs.x.ax = 0x4F05;
1048     regs.x.bx = 0x0000;
1049     regs.x.dx = bank;
1050     PM_int86(0x10,&regs,&regs);
1051 }
1052
1053 /****************************************************************************
1054 REMARKS:
1055 Call the VBE/Core software interrupt to change display banks.
1056 ****************************************************************************/
1057 void PMAPI PM_setBankAB(
1058     int bank)
1059 {
1060     RMREGS  regs;
1061     regs.x.ax = 0x4F05;
1062     regs.x.bx = 0x0000;
1063     regs.x.dx = bank;
1064     PM_int86(0x10,&regs,&regs);
1065     regs.x.ax = 0x4F05;
1066     regs.x.bx = 0x0001;
1067     regs.x.dx = bank;
1068     PM_int86(0x10,&regs,&regs);
1069 }
1070
1071 /****************************************************************************
1072 REMARKS:
1073 Call the VBE/Core software interrupt to change display start address.
1074 ****************************************************************************/
1075 void PMAPI PM_setCRTStart(
1076     int x,
1077     int y,
1078     int waitVRT)
1079 {
1080     RMREGS  regs;
1081     regs.x.ax = 0x4F07;
1082     regs.x.bx = waitVRT;
1083     regs.x.cx = x;
1084     regs.x.dx = y;
1085     PM_int86(0x10,&regs,&regs);
1086 }
1087
1088 /****************************************************************************
1089 REMARKS:
1090 Enable write combining for the memory region.
1091 ****************************************************************************/
1092 ibool PMAPI PM_enableWriteCombine(
1093     ulong base,
1094     ulong length,
1095     uint type)
1096 {
1097     DWORD   inBuf[3];   /* Buffer to send data to VxD       */
1098     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
1099     DWORD   count;      /* Count of bytes returned from VxD */
1100
1101     if (!inited)
1102         PM_init();
1103     inBuf[0] = base;
1104     inBuf[1] = length;
1105     inBuf[2] = type;
1106     CHECK_FOR_PMHELP();
1107     if (DeviceIoControl(_PM_hDevice, PMHELP_ENABLELFBCOMB32, inBuf, sizeof(inBuf),
1108             outBuf, sizeof(outBuf), &count, NULL))
1109         return outBuf[0];
1110     return false;
1111 }
1112
1113 /****************************************************************************
1114 REMARKS:
1115 Get the page directory base register value
1116 ****************************************************************************/
1117 ulong PMAPI _PM_getPDB(void)
1118 {
1119     DWORD   outBuf[1];  /* Buffer to receive data from VxD  */
1120     DWORD   count;      /* Count of bytes returned from VxD */
1121
1122     CHECK_FOR_PMHELP();
1123     if (DeviceIoControl(_PM_hDevice, PMHELP_GETPDB32, NULL, 0,
1124             outBuf, sizeof(outBuf), &count, NULL))
1125         return outBuf[0];
1126     return 0;
1127 }
1128
1129 /****************************************************************************
1130 REMARKS:
1131 Flush the translation lookaside buffer.
1132 ****************************************************************************/
1133 void PMAPI PM_flushTLB(void)
1134 {
1135     CHECK_FOR_PMHELP();
1136     DeviceIoControl(_PM_hDevice, PMHELP_FLUSHTLB32, NULL, 0, NULL, 0, NULL, NULL);
1137 }
1138
1139 /****************************************************************************
1140 REMARKS:
1141 Execute the POST on the secondary BIOS for a controller.
1142 ****************************************************************************/
1143 ibool PMAPI PM_doBIOSPOST(
1144     ushort axVal,
1145     ulong BIOSPhysAddr,
1146     void *mappedBIOS,
1147     ulong BIOSLen)
1148 {
1149     /* This is never done by Win32 programs, but rather done by the VxD
1150      * when the system boots.
1151      */
1152     (void)axVal;
1153     (void)BIOSPhysAddr;
1154     (void)mappedBIOS;
1155     (void)BIOSLen;
1156     return false;
1157 }
1158
1159 /****************************************************************************
1160 REMARKS:
1161 Load an OS specific shared library or DLL. If the OS does not support
1162 shared libraries, simply return NULL.
1163 ****************************************************************************/
1164 PM_MODULE PMAPI PM_loadLibrary(
1165     const char *szDLLName)
1166 {
1167     return (PM_MODULE)LoadLibrary(szDLLName);
1168 }
1169
1170 /****************************************************************************
1171 REMARKS:
1172 Get the address of a named procedure from a shared library.
1173 ****************************************************************************/
1174 void * PMAPI PM_getProcAddress(
1175     PM_MODULE hModule,
1176     const char *szProcName)
1177 {
1178     return (void*)GetProcAddress((HINSTANCE)hModule,szProcName);
1179 }
1180
1181 /****************************************************************************
1182 REMARKS:
1183 Unload a shared library.
1184 ****************************************************************************/
1185 void PMAPI PM_freeLibrary(
1186     PM_MODULE hModule)
1187 {
1188     FreeLibrary((HINSTANCE)hModule);
1189 }
1190
1191 /****************************************************************************
1192 REMARKS:
1193 Internal function to convert the find data to the generic interface.
1194 ****************************************************************************/
1195 static void convertFindData(
1196     PM_findData *findData,
1197     WIN32_FIND_DATA *blk)
1198 {
1199     ulong   dwSize = findData->dwSize;
1200
1201     memset(findData,0,findData->dwSize);
1202     findData->dwSize = dwSize;
1203     if (blk->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1204         findData->attrib |= PM_FILE_READONLY;
1205     if (blk->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1206         findData->attrib |= PM_FILE_DIRECTORY;
1207     if (blk->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
1208         findData->attrib |= PM_FILE_ARCHIVE;
1209     if (blk->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
1210         findData->attrib |= PM_FILE_HIDDEN;
1211     if (blk->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
1212         findData->attrib |= PM_FILE_SYSTEM;
1213     findData->sizeLo = blk->nFileSizeLow;
1214     findData->sizeHi = blk->nFileSizeHigh;
1215     strncpy(findData->name,blk->cFileName,PM_MAX_PATH);
1216     findData->name[PM_MAX_PATH-1] = 0;
1217 }
1218
1219 /****************************************************************************
1220 REMARKS:
1221 Function to find the first file matching a search criteria in a directory.
1222 ****************************************************************************/
1223 void *PMAPI PM_findFirstFile(
1224     const char *filename,
1225     PM_findData *findData)
1226 {
1227     WIN32_FIND_DATA blk;
1228     HANDLE          hfile;
1229
1230     if ((hfile = FindFirstFile(filename,&blk)) != INVALID_HANDLE_VALUE) {
1231         convertFindData(findData,&blk);
1232         return (void*)hfile;
1233         }
1234     return PM_FILE_INVALID;
1235 }
1236
1237 /****************************************************************************
1238 REMARKS:
1239 Function to find the next file matching a search criteria in a directory.
1240 ****************************************************************************/
1241 ibool PMAPI PM_findNextFile(
1242     void *handle,
1243     PM_findData *findData)
1244 {
1245     WIN32_FIND_DATA blk;
1246
1247     if (FindNextFile((HANDLE)handle,&blk)) {
1248         convertFindData(findData,&blk);
1249         return true;
1250         }
1251     return false;
1252 }
1253
1254 /****************************************************************************
1255 REMARKS:
1256 Function to close the find process
1257 ****************************************************************************/
1258 void PMAPI PM_findClose(
1259     void *handle)
1260 {
1261     FindClose((HANDLE)handle);
1262 }
1263
1264 /****************************************************************************
1265 REMARKS:
1266 Function to determine if a drive is a valid drive or not. Under Unix this
1267 function will return false for anything except a value of 3 (considered
1268 the root drive, and equivalent to C: for non-Unix systems). The drive
1269 numbering is:
1270
1271     1   - Drive A:
1272     2   - Drive B:
1273     3   - Drive C:
1274     etc
1275
1276 ****************************************************************************/
1277 ibool PMAPI PM_driveValid(
1278     char drive)
1279 {
1280     char    buf[5];
1281     int     type;
1282
1283     sprintf(buf,"%c:\\", drive);
1284     return ((type = GetDriveType(buf)) != 0 && type != 1);
1285 }
1286
1287 /****************************************************************************
1288 REMARKS:
1289 Function to get the current working directory for the specififed drive.
1290 Under Unix this will always return the current working directory regardless
1291 of what the value of 'drive' is.
1292 ****************************************************************************/
1293 void PMAPI PM_getdcwd(
1294     int drive,
1295     char *dir,
1296     int len)
1297 {
1298     /* NT stores the current directory for drive N in the magic environment */
1299     /* variable =N: so we simply look for that environment variable. */
1300     char envname[4];
1301
1302     envname[0] = '=';
1303     envname[1] = drive - 1 + 'A';
1304     envname[2] = ':';
1305     envname[3] = '\0';
1306     if (GetEnvironmentVariable(envname,dir,len) == 0) {
1307         /* The current directory or the drive has not been set yet, so */
1308         /* simply set it to the root. */
1309         dir[0] = envname[1];
1310         dir[1] = ':';
1311         dir[2] = '\\';
1312         dir[3] = '\0';
1313         SetEnvironmentVariable(envname,dir);
1314         }
1315 }
1316
1317 /****************************************************************************
1318 REMARKS:
1319 Function to change the file attributes for a specific file.
1320 ****************************************************************************/
1321 void PMAPI PM_setFileAttr(
1322     const char *filename,
1323     uint attrib)
1324 {
1325     DWORD attr = 0;
1326
1327     if (attrib & PM_FILE_READONLY)
1328         attr |= FILE_ATTRIBUTE_READONLY;
1329     if (attrib & PM_FILE_ARCHIVE)
1330         attr |= FILE_ATTRIBUTE_ARCHIVE;
1331     if (attrib & PM_FILE_HIDDEN)
1332         attr |= FILE_ATTRIBUTE_HIDDEN;
1333     if (attrib & PM_FILE_SYSTEM)
1334         attr |= FILE_ATTRIBUTE_SYSTEM;
1335     SetFileAttributes((LPSTR)filename, attr);
1336 }
1337
1338 /****************************************************************************
1339 REMARKS:
1340 Function to get the file attributes for a specific file.
1341 ****************************************************************************/
1342 uint PMAPI PM_getFileAttr(
1343     const char *filename)
1344 {
1345     DWORD   attr = GetFileAttributes(filename);
1346     uint    attrib = 0;
1347
1348     if (attr & FILE_ATTRIBUTE_READONLY)
1349         attrib |= PM_FILE_READONLY;
1350     if (attr & FILE_ATTRIBUTE_ARCHIVE)
1351         attrib |= PM_FILE_ARCHIVE;
1352     if (attr & FILE_ATTRIBUTE_HIDDEN)
1353         attrib |= PM_FILE_HIDDEN;
1354     if (attr & FILE_ATTRIBUTE_SYSTEM)
1355         attrib |= PM_FILE_SYSTEM;
1356     return attrib;
1357 }
1358
1359 /****************************************************************************
1360 REMARKS:
1361 Function to create a directory.
1362 ****************************************************************************/
1363 ibool PMAPI PM_mkdir(
1364     const char *filename)
1365 {
1366     return CreateDirectory(filename,NULL);
1367 }
1368
1369 /****************************************************************************
1370 REMARKS:
1371 Function to remove a directory.
1372 ****************************************************************************/
1373 ibool PMAPI PM_rmdir(
1374     const char *filename)
1375 {
1376     return RemoveDirectory(filename);
1377 }
1378
1379 /****************************************************************************
1380 REMARKS:
1381 Function to get the file time and date for a specific file.
1382 ****************************************************************************/
1383 ibool PMAPI PM_getFileTime(
1384     const char *filename,
1385     ibool gmTime,
1386     PM_time *time)
1387 {
1388     HFILE       f;
1389     OFSTRUCT    of;
1390     FILETIME    utcTime,localTime;
1391     SYSTEMTIME  sysTime;
1392     ibool       status = false;
1393
1394     of.cBytes = sizeof(of);
1395     if ((f = OpenFile(filename,&of,OF_READ)) == HFILE_ERROR)
1396         return false;
1397     if (!GetFileTime((HANDLE)f,NULL,NULL,&utcTime))
1398         goto Exit;
1399     if (!gmTime) {
1400         if (!FileTimeToLocalFileTime(&utcTime,&localTime))
1401             goto Exit;
1402         }
1403     else
1404         localTime = utcTime;
1405     if (!FileTimeToSystemTime(&localTime,&sysTime))
1406         goto Exit;
1407     time->year = sysTime.wYear;
1408     time->mon = sysTime.wMonth-1;
1409     time->day = sysTime.wYear;
1410     time->hour = sysTime.wHour;
1411     time->min = sysTime.wMinute;
1412     time->sec = sysTime.wSecond;
1413     status = true;
1414
1415 Exit:
1416     CloseHandle((HANDLE)f);
1417     return status;
1418 }
1419
1420 /****************************************************************************
1421 REMARKS:
1422 Function to set the file time and date for a specific file.
1423 ****************************************************************************/
1424 ibool PMAPI PM_setFileTime(
1425     const char *filename,
1426     ibool gmTime,
1427     PM_time *time)
1428 {
1429     HFILE       f;
1430     OFSTRUCT    of;
1431     FILETIME    utcTime,localTime;
1432     SYSTEMTIME  sysTime;
1433     ibool       status = false;
1434
1435     of.cBytes = sizeof(of);
1436     if ((f = OpenFile(filename,&of,OF_WRITE)) == HFILE_ERROR)
1437         return false;
1438     sysTime.wYear = time->year;
1439     sysTime.wMonth = time->mon+1;
1440     sysTime.wYear = time->day;
1441     sysTime.wHour = time->hour;
1442     sysTime.wMinute = time->min;
1443     sysTime.wSecond = time->sec;
1444     if (!SystemTimeToFileTime(&sysTime,&localTime))
1445         goto Exit;
1446     if (!gmTime) {
1447         if (!LocalFileTimeToFileTime(&localTime,&utcTime))
1448             goto Exit;
1449         }
1450     else
1451         utcTime = localTime;
1452     if (!SetFileTime((HANDLE)f,NULL,NULL,&utcTime))
1453         goto Exit;
1454     status = true;
1455
1456 Exit:
1457     CloseHandle((HANDLE)f);
1458     return status;
1459 }