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