1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20#include <sys/segments.h>
21#include <go32.h>
22#include <unistd.h>
23#include <sys/nearptr.h>
24#include <dos.h>
25#include <string.h>
26#include <dpmi.h>
27// #include <osfcn.h>
28#include <bios.h>
29
30#include "dosisms.h"
31
32_go32_dpmi_registers hmm;
33
34// globals
35regs_t regs;
36void (*dos_error_func)(char *msg, ...);
37
38static unsigned conventional_memory = -1;
39
40__dpmi_regs callback_regs;
41
42void map_in_conventional_memory(void)
43{
44	if (conventional_memory == -1)
45	{
46		if (__djgpp_nearptr_enable())
47		{
48			conventional_memory = __djgpp_conventional_base;
49		}
50	}
51}
52
53unsigned int ptr2real(void *ptr)
54{
55	map_in_conventional_memory();
56	return (int)ptr - conventional_memory;
57}
58
59void *real2ptr(unsigned int real)
60{
61	map_in_conventional_memory();
62	return (void *) (real + conventional_memory);
63}
64
65void *far2ptr(unsigned int farptr)
66{
67	return real2ptr(((farptr & ~0xffff) >>12) + (farptr&0xffff));
68}
69
70unsigned int ptr2far(void *ptr)
71{
72	return ((ptr2real(ptr)&~0xf) << 12) + (ptr2real(ptr) & 0xf);
73}
74
75int dos_inportb(int port)
76{
77	return inportb(port);
78}
79
80int dos_inportw(int port)
81{
82	return inportw(port);
83}
84
85void dos_outportb(int port, int val)
86{
87	outportb(port, val);
88}
89
90void dos_outportw(int port, int val)
91{
92	outportw(port, val);
93}
94
95void dos_irqenable(void)
96{
97	enable();
98}
99
100void dos_irqdisable(void)
101{
102	disable();
103}
104
105//
106// Returns 0 on success
107//
108
109int	dos_int86(int vec)
110{
111    int rc;
112    regs.x.ss = regs.x.sp = 0;
113    rc = _go32_dpmi_simulate_int(vec, (_go32_dpmi_registers *) &regs);
114    return rc || (regs.x.flags & 1);
115}
116
117int	dos_int386(int vec, regs_t *inregs, regs_t *outregs)
118{
119	int rc;
120	memcpy(outregs, inregs, sizeof(regs_t));
121	outregs->x.ss = outregs->x.sp = 0;
122	rc = _go32_dpmi_simulate_int(vec, (_go32_dpmi_registers *) outregs);
123	return rc || (outregs->x.flags & 1);
124}
125
126//
127// Because of a quirk in dj's alloc-dos-memory wrapper, you need to keep
128// the seginfo structure around for when you free the mem.
129//
130
131static _go32_dpmi_seginfo seginfo[10];
132
133void *dos_getmemory(int size)
134{
135
136	int rc;
137	_go32_dpmi_seginfo info;
138	static int firsttime=1;
139	int i;
140
141	if (firsttime)
142	{
143		memset(seginfo, 0, sizeof(seginfo));
144		firsttime = 0;
145	}
146
147	info.size = (size+15) / 16;
148	rc = _go32_dpmi_allocate_dos_memory(&info);
149	if (rc)
150		return 0;
151
152	for (i=0;i<10;i++)
153		if (!seginfo[i].rm_segment) break;
154	seginfo[i] = info;
155	return real2ptr((int) info.rm_segment << 4);
156
157}
158
159void dos_freememory(void *ptr)
160{
161
162	int i;
163	int segment;
164
165	segment = ptr2real(ptr) >> 4;
166	for (i=0 ; i<10 ; i++)
167		if (seginfo[i].rm_segment == segment)
168		{
169			_go32_dpmi_free_dos_memory(&seginfo[i]);
170			seginfo[i].rm_segment = 0;
171			break;
172		}
173
174}
175
176static struct handlerhistory_s
177{
178	int intr;
179	_go32_dpmi_seginfo pm_oldvec;
180} handlerhistory[4];
181
182static int handlercount=0;
183
184void	dos_registerintr(int intr, void (*handler)(void))
185{
186	_go32_dpmi_seginfo info;
187	struct handlerhistory_s *oldstuff;
188
189	oldstuff = &handlerhistory[handlercount];
190
191// remember old handler
192	_go32_dpmi_get_protected_mode_interrupt_vector(intr, &oldstuff->pm_oldvec);
193	oldstuff->intr = intr;
194
195	info.pm_offset = (int) handler;
196	_go32_dpmi_allocate_iret_wrapper(&info);
197
198// set new protected mode handler
199	_go32_dpmi_set_protected_mode_interrupt_vector(intr, &info);
200
201	handlercount++;
202
203}
204
205void	dos_restoreintr(int intr)
206{
207
208	int i;
209	struct handlerhistory_s *oldstuff;
210
211// find and reinstall previous interrupt
212	for (i=0 ; i<handlercount ; i++)
213	{
214		oldstuff = &handlerhistory[i];
215		if (oldstuff->intr == intr)
216		{
217			_go32_dpmi_set_protected_mode_interrupt_vector(intr,
218				&oldstuff->pm_oldvec);
219			oldstuff->intr = -1;
220			break;
221		}
222	}
223
224}
225
226void	dos_usleep(int usecs)
227{
228	usleep(usecs);
229}
230
231int dos_getheapsize(void)
232{
233	return _go32_dpmi_remaining_physical_memory();
234}
235
236int dos_lockmem(void *addr, int size)
237{
238	__dpmi_meminfo info;
239	info.address = (long) addr + __djgpp_base_address;
240	info.size = size;
241	if (__dpmi_lock_linear_region(&info))
242		return __dpmi_error;
243	else
244		return 0;
245}
246
247int dos_unlockmem(void *addr, int size)
248{
249	__dpmi_meminfo info;
250	info.address = (long) addr + __djgpp_base_address;
251	info.size = size;
252	if (__dpmi_unlock_linear_region(&info))
253		return __dpmi_error;
254	else
255		return 0;
256}
257
258