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         _outp(addr, value);
116 #endif
117     }
118 }
119 
ssi2001_inb(unsigned int addrint)120 static BYTE ssi2001_inb(unsigned int addrint)
121 {
122     WORD addr = (WORD)addrint;
123     DWORD tmp;
124     BYTE retval = 0;
125 
126     /* make sure the above conversion did not loose any details */
127     assert(addr == addrint);
128 
129     if (ssi2001_use_lib) {
130         if (ssi2001_use_winio_dll) {
131             winio_inp32fp(addr, &tmp, 1);
132             retval = (BYTE)tmp;
133         } else {
134             retval = (BYTE)inpout_inp32fp(addr);
135         }
136     } else {
137 #ifdef  _M_IX86
138         return _inp(addr);
139 #endif
140     }
141     return retval;
142 }
143 
ssi2001_drv_read(uint16_t addr,int chipno)144 int ssi2001_drv_read(uint16_t addr, int chipno)
145 {
146     if (chipno < MAXSID && addr < 0x20) {
147         return ssi2001_inb(SSI2008_BASE + (addr & 0x1f));
148     }
149     return 0;
150 }
151 
ssi2001_drv_store(uint16_t addr,uint8_t outval,int chipno)152 void ssi2001_drv_store(uint16_t addr, uint8_t outval, int chipno)
153 {
154     if (chipno < MAXSID && addr < 0x20) {
155         ssi2001_outb(SSI2008_BASE + (addr & 0x1f), outval);
156     }
157 }
158 
159 /*----------------------------------------------------------------------*/
160 
161 static HINSTANCE hLib = NULL;
162 
163 #if defined(__amd64__) || defined(__x86_64__)
164 #  define INPOUTDLLNAME "inpoutx64.dll"
165 #  define WINIODLLNAME  "winio64.dll"
166 #else
167 #  define INPOUTDLLNAME "inpout32.dll"
168 #  define WINIODLLNAME  "winio32.dll"
169 #  define WINIOOLDNAME  "winio.dll"
170 #endif
171 
detect_sid(void)172 static int detect_sid(void)
173 {
174     int i;
175 
176     for (i = 0x18; i >= 0; --i) {
177         ssi2001_drv_store((WORD)i, 0, 0);
178     }
179 
180     ssi2001_drv_store(0x12, 0xff, 0);
181 
182     for (i = 0; i < 100; ++i) {
183         if (ssi2001_drv_read(0x1b, 0)) {
184             return 0;
185         }
186     }
187 
188     ssi2001_drv_store(0x0e, 0xff, 0);
189     ssi2001_drv_store(0x0f, 0xff, 0);
190     ssi2001_drv_store(0x12, 0x20, 0);
191 
192     for (i = 0; i < 100; ++i) {
193         if (ssi2001_drv_read(0x1b, 0)) {
194             return 1;
195         }
196     }
197     return 0;
198 }
199 
close_device(void)200 static void close_device(void)
201 {
202     if (ssi2001_use_lib) {
203         if (ssi2001_use_winio_dll) {
204             shutdown32fp();
205         }
206         FreeLibrary(hLib);
207         hLib = NULL;
208         ssi2001_use_winio_dll = 0;
209         ssi2001_use_inpout_dll = 0;
210     }
211 }
212 
ssi2001_drv_open(void)213 int ssi2001_drv_open(void)
214 {
215     char *libname = NULL;
216 
217     if (!sids_found) {
218         return -1;
219     }
220 
221     if (sids_found > 0) {
222         return 0;
223     }
224 
225     sids_found = 0;
226 
227     log_message(LOG_DEFAULT, "Detecting ISA SSI2001 boards.");
228 
229 #ifdef WINIOOLDNAME
230     if (hLib == NULL) {
231         libname = WINIOOLDNAME;
232         hLib = LoadLibrary(libname);
233         ssi2001_use_inpout_dll = 0;
234         ssi2001_use_winio_dll = 1;
235     }
236 #endif
237 
238     if (hLib == NULL) {
239         libname = WINIODLLNAME;
240         hLib = LoadLibrary(libname);
241         ssi2001_use_inpout_dll = 0;
242         ssi2001_use_winio_dll = 1;
243     }
244 
245     if (hLib == NULL) {
246         libname = INPOUTDLLNAME;
247         hLib = LoadLibrary(libname);
248         ssi2001_use_inpout_dll = 1;
249         ssi2001_use_winio_dll = 0;
250     }
251 
252     ssi2001_use_lib = 0;
253 
254     if (hLib != NULL) {
255         log_message(LOG_DEFAULT, "Opened %s.", libname);
256 
257         if (ssi2001_use_inpout_dll) {
258             inpout_inp32fp = (inpout_inpfuncPtr)GetProcAddress(hLib, "Inp32");
259             if (inpout_inp32fp != NULL) {
260                 inpout_oup32fp = (inpout_oupfuncPtr)GetProcAddress(hLib, "Out32");
261                 if (inpout_oup32fp != NULL) {
262                     log_message(LOG_DEFAULT, "Using %s for ISA I/O access.", libname);
263                     ssi2001_use_lib = 1;
264                 }
265             }
266         } else {
267             winio_inp32fp = (winio_inpfuncPtr)GetProcAddress(hLib, "GetPortVal");
268             if (winio_inp32fp != NULL) {
269                 winio_oup32fp = (winio_oupfuncPtr)GetProcAddress(hLib, "SetPortVal");
270                 if (winio_oup32fp != NULL) {
271                     init32fp = (initfuncPtr)GetProcAddress(hLib, "InitializeWinIo");
272                     if (init32fp != NULL) {
273                         shutdown32fp = (shutdownfuncPtr)GetProcAddress(hLib, "ShutdownWinIo");
274                         if (shutdown32fp != NULL) {
275                             if (init32fp()) {
276                                 log_message(LOG_DEFAULT, "Using %s for ISA I/O access.", libname);
277                                 ssi2001_use_lib = 1;
278                             } else {
279                                 log_message(LOG_DEFAULT, "Cannot init %s.", libname);
280                             }
281                         }
282                     }
283                 }
284             }
285         }
286         if (!ssi2001_use_lib) {
287             log_message(LOG_DEFAULT, "Cannot get I/O functions in %s, using direct I/O access.", libname);
288         }
289     } else {
290         log_message(LOG_DEFAULT, "Cannot open %s, trying direct ISA I/O access.", libname);
291     }
292 
293     if (!(GetVersion() & 0x80000000) && ssi2001_use_lib == 0) {
294         log_message(LOG_DEFAULT, "Cannot use direct I/O access on Windows NT/2000/Server/XP/Vista/7/8/10.");
295         return -1;
296     }
297 
298     if (detect_sid()) {
299         sids_found = 1;
300         log_message(LOG_DEFAULT, "ISA SSI2001 SID: opened.");
301         return 0;
302     }
303 
304     log_message(LOG_DEFAULT, "No ISA SSI2001 found.");
305 
306     close_device();
307 
308     return -1;
309 }
310 
ssi2001_drv_close(void)311 int ssi2001_drv_close(void)
312 {
313     close_device();
314 
315     sids_found = -1;
316 
317     log_message(LOG_DEFAULT, "ISA SSI2001 SID: closed.");
318 
319     return 0;
320 }
321 
ssi2001_drv_available(void)322 int ssi2001_drv_available(void)
323 {
324     return sids_found;
325 }
326 #endif
327 #endif
328