1 /*
2 * ssi2001-win32-drv.c - SSI2001 (ISA SID card) support for WIN32.
3 *
4 * Written by
5 * Marco van den Heuvel <blackystardust68@yahoo.com>
6 *
7 * This file is part of VICE, the Versatile Commodore Emulator.
8 * See README for copyright notice.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA.
24 *
25 */
26
27 /* Tested and confirmed working on:
28
29 - Windows 95C (Direct ISA I/O, inpout32.dll is incompatible with windows 95)
30 - Windows 98SE (winio.dll ISA I/O)
31 - Windows 98SE (inpout32.dll ISA I/O)
32 - Windows 98SE (Direct ISA I/O)
33 - Windows ME (winio.dll ISA I/O)
34 - Windows ME (inpout32.dll ISA I/O)
35 - Windows ME (Direct ISA I/O)
36 - Windows NT 3.51 (inpout32.dll ISA I/O)
37 - Windows NT 4.0 (winio32.dll ISA I/O)
38 - Windows NT 4.0 (inpout32.dll ISA I/O)
39 - Windows 2000 (winio32.dll ISA I/O)
40 - Windows 2000 (inpout32.dll ISA I/O)
41 - Windows XP (winio32.dll ISA I/O)
42 - Windows XP (inpout32.dll ISA I/O)
43 - Windows 2003 Server (winio32.dll ISA I/O)
44 - Windows 2003 Server (inpout32.dll ISA I/O)
45 */
46
47 #include "vice.h"
48
49 #ifdef WIN32_COMPILE
50
51 #ifdef HAVE_SSI2001
52 #include <windows.h>
53 #include <fcntl.h>
54 #include <stdio.h>
55 #include <assert.h>
56
57 #include "log.h"
58 #include "types.h"
59 #include "wininpoutp.h"
60
61 #include "ssi2001.h"
62
63 #define SSI2008_BASE 0x280
64
65 static int ssi2001_use_lib = 0;
66 static int ssi2001_use_inpout_dll = 0;
67 static int ssi2001_use_winio_dll = 0;
68
69 #define MAXSID 1
70
71 static int sids_found = -1;
72
73 #ifndef MSVC_RC
74 typedef short _stdcall (*inpout_inpfuncPtr)(short portaddr);
75 typedef void _stdcall (*inpout_oupfuncPtr)(short portaddr, short datum);
76
77 typedef int _stdcall (*initfuncPtr)(void);
78 typedef void _stdcall (*shutdownfuncPtr)(void);
79 typedef int _stdcall (*winio_inpfuncPtr)(WORD port, PDWORD value, BYTE size);
80 typedef int _stdcall (*winio_oupfuncPtr)(WORD port, DWORD value, BYTE size);
81 #else
82 typedef short (CALLBACK* inpout_inpfuncPtr)(short);
83 typedef void (CALLBACK* inpout_oupfuncPtr)(short, short);
84
85 typedef int (CALLBACK* initfuncPtr)(void);
86 typedef void (CALLBACK* shutdownfuncPtr)(void);
87 typedef int (CALLBACK* winio_inpfuncPtr)(WORD, PDWORD, BYTE);
88 typedef int (CALLBACK* winio_oupfuncPtr)(WORD, DWORD, BYTE);
89 #endif
90
91 static inpout_inpfuncPtr inpout_inp32fp;
92 static inpout_oupfuncPtr inpout_oup32fp;
93
94 static initfuncPtr init32fp;
95 static shutdownfuncPtr shutdown32fp;
96 static winio_inpfuncPtr winio_inp32fp;
97 static winio_oupfuncPtr winio_oup32fp;
98
99 /* input/output functions */
ssi2001_outb(unsigned int addrint,short value)100 static void ssi2001_outb(unsigned int addrint, short value)
101 {
102 WORD addr = (WORD)addrint;
103
104 /* make sure the above conversion did not loose any details */
105 assert(addr == addrint);
106
107 if (ssi2001_use_lib) {
108 if (ssi2001_use_winio_dll) {
109 winio_oup32fp(addr, (DWORD)value, 1);
110 } else {
111 inpout_oup32fp(addr, (WORD)value);
112 }
113 } else {
114 #ifdef _M_IX86
115 #ifdef WATCOM_COMPILE
116 outp(addr, value);
117 #else
118 _outp(addr, value);
119 #endif
120 #endif
121 }
122 }
123
ssi2001_inb(unsigned int addrint)124 static BYTE ssi2001_inb(unsigned int addrint)
125 {
126 WORD addr = (WORD)addrint;
127 DWORD tmp;
128 BYTE retval = 0;
129
130 /* make sure the above conversion did not loose any details */
131 assert(addr == addrint);
132
133 if (ssi2001_use_lib) {
134 if (ssi2001_use_winio_dll) {
135 winio_inp32fp(addr, &tmp, 1);
136 retval = (BYTE)tmp;
137 } else {
138 retval = (BYTE)inpout_inp32fp(addr);
139 }
140 } else {
141 #ifdef _M_IX86
142 #ifdef WATCOM_COMPILE
143 return inp(addr);
144 #else
145 return _inp(addr);
146 #endif
147 #endif
148 }
149 return retval;
150 }
151
ssi2001_drv_read(uint16_t addr,int chipno)152 int ssi2001_drv_read(uint16_t addr, int chipno)
153 {
154 if (chipno < MAXSID && addr < 0x20) {
155 return ssi2001_inb(SSI2008_BASE + (addr & 0x1f));
156 }
157 return 0;
158 }
159
ssi2001_drv_store(uint16_t addr,uint8_t outval,int chipno)160 void ssi2001_drv_store(uint16_t addr, uint8_t outval, int chipno)
161 {
162 if (chipno < MAXSID && addr < 0x20) {
163 ssi2001_outb(SSI2008_BASE + (addr & 0x1f), outval);
164 }
165 }
166
167 /*----------------------------------------------------------------------*/
168
169 static HINSTANCE hLib = NULL;
170
171 #ifdef _MSC_VER
172 # ifdef _WIN64
173 # define INPOUTDLLNAME "inpoutx64.dll"
174 # define WINIODLLNAME "winio64.dll"
175 # else
176 # define INPOUTDLLNAME "inpout32.dll"
177 # define WINIODLLNAME "winio32.dll"
178 # define WINIOOLDNAME "winio.dll"
179 # endif
180 #else
181 # if defined(__amd64__) || defined(__x86_64__)
182 # define INPOUTDLLNAME "inpoutx64.dll"
183 # define WINIODLLNAME "winio64.dll"
184 # else
185 # define INPOUTDLLNAME "inpout32.dll"
186 # define WINIODLLNAME "winio32.dll"
187 # define WINIOOLDNAME "winio.dll"
188 # endif
189 #endif
190
detect_sid(void)191 static int detect_sid(void)
192 {
193 int i;
194
195 for (i = 0x18; i >= 0; --i) {
196 ssi2001_drv_store((WORD)i, 0, 0);
197 }
198
199 ssi2001_drv_store(0x12, 0xff, 0);
200
201 for (i = 0; i < 100; ++i) {
202 if (ssi2001_drv_read(0x1b, 0)) {
203 return 0;
204 }
205 }
206
207 ssi2001_drv_store(0x0e, 0xff, 0);
208 ssi2001_drv_store(0x0f, 0xff, 0);
209 ssi2001_drv_store(0x12, 0x20, 0);
210
211 for (i = 0; i < 100; ++i) {
212 if (ssi2001_drv_read(0x1b, 0)) {
213 return 1;
214 }
215 }
216 return 0;
217 }
218
close_device(void)219 static void close_device(void)
220 {
221 if (ssi2001_use_lib) {
222 if (ssi2001_use_winio_dll) {
223 shutdown32fp();
224 }
225 FreeLibrary(hLib);
226 hLib = NULL;
227 ssi2001_use_winio_dll = 0;
228 ssi2001_use_inpout_dll = 0;
229 }
230 }
231
ssi2001_drv_open(void)232 int ssi2001_drv_open(void)
233 {
234 char *libname = NULL;
235
236 if (!sids_found) {
237 return -1;
238 }
239
240 if (sids_found > 0) {
241 return 0;
242 }
243
244 sids_found = 0;
245
246 log_message(LOG_DEFAULT, "Detecting ISA SSI2001 boards.");
247
248 #ifdef WINIOOLDNAME
249 if (hLib == NULL) {
250 libname = WINIOOLDNAME;
251 hLib = LoadLibrary(libname);
252 ssi2001_use_inpout_dll = 0;
253 ssi2001_use_winio_dll = 1;
254 }
255 #endif
256
257 if (hLib == NULL) {
258 libname = WINIODLLNAME;
259 hLib = LoadLibrary(libname);
260 ssi2001_use_inpout_dll = 0;
261 ssi2001_use_winio_dll = 1;
262 }
263
264 if (hLib == NULL) {
265 libname = INPOUTDLLNAME;
266 hLib = LoadLibrary(libname);
267 ssi2001_use_inpout_dll = 1;
268 ssi2001_use_winio_dll = 0;
269 }
270
271 ssi2001_use_lib = 0;
272
273 if (hLib != NULL) {
274 log_message(LOG_DEFAULT, "Opened %s.", libname);
275
276 if (ssi2001_use_inpout_dll) {
277 inpout_inp32fp = (inpout_inpfuncPtr)GetProcAddress(hLib, "Inp32");
278 if (inpout_inp32fp != NULL) {
279 inpout_oup32fp = (inpout_oupfuncPtr)GetProcAddress(hLib, "Out32");
280 if (inpout_oup32fp != NULL) {
281 log_message(LOG_DEFAULT, "Using %s for ISA I/O access.", libname);
282 ssi2001_use_lib = 1;
283 }
284 }
285 } else {
286 winio_inp32fp = (winio_inpfuncPtr)GetProcAddress(hLib, "GetPortVal");
287 if (winio_inp32fp != NULL) {
288 winio_oup32fp = (winio_oupfuncPtr)GetProcAddress(hLib, "SetPortVal");
289 if (winio_oup32fp != NULL) {
290 init32fp = (initfuncPtr)GetProcAddress(hLib, "InitializeWinIo");
291 if (init32fp != NULL) {
292 shutdown32fp = (shutdownfuncPtr)GetProcAddress(hLib, "ShutdownWinIo");
293 if (shutdown32fp != NULL) {
294 if (init32fp()) {
295 log_message(LOG_DEFAULT, "Using %s for ISA I/O access.", libname);
296 ssi2001_use_lib = 1;
297 } else {
298 log_message(LOG_DEFAULT, "Cannot init %s.", libname);
299 }
300 }
301 }
302 }
303 }
304 }
305 if (!ssi2001_use_lib) {
306 log_message(LOG_DEFAULT, "Cannot get I/O functions in %s, using direct I/O access.", libname);
307 }
308 } else {
309 log_message(LOG_DEFAULT, "Cannot open %s, trying direct ISA I/O access.", libname);
310 }
311
312 if (!(GetVersion() & 0x80000000) && ssi2001_use_lib == 0) {
313 log_message(LOG_DEFAULT, "Cannot use direct I/O access on Windows NT/2000/Server/XP/Vista/7/8/10.");
314 return -1;
315 }
316
317 if (detect_sid()) {
318 sids_found = 1;
319 log_message(LOG_DEFAULT, "ISA SSI2001 SID: opened.");
320 return 0;
321 }
322
323 log_message(LOG_DEFAULT, "No ISA SSI2001 found.");
324
325 close_device();
326
327 return -1;
328 }
329
ssi2001_drv_close(void)330 int ssi2001_drv_close(void)
331 {
332 close_device();
333
334 sids_found = -1;
335
336 log_message(LOG_DEFAULT, "ISA SSI2001 SID: closed.");
337
338 return 0;
339 }
340
ssi2001_drv_available(void)341 int ssi2001_drv_available(void)
342 {
343 return sids_found;
344 }
345 #endif
346 #endif
347