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