1 /** \file cw-win32-pci.c
2 * \brief Windows specific PCI cw3 driver
3 *
4 * \author Marco van den Heuvel <blackystardust68@yahoo.com>
5 *
6 * This file is part of VICE, the Versatile Commodore Emulator.
7 * See README for copyright notice.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 * 02111-1307 USA.
23 *
24 */
25
26 /* Tested and confirmed working on:
27
28 - Windows 95C (Direct PCI I/O)
29 - Windows 98SE (Direct PCI I/O)
30 - Windows ME (Direct PCI I/O)
31 - Windows NT 4 (winio32.dll PCI I/O)
32 - Windows 2000 (winio32.dll PCI I/O)
33 - Windows XP (winio32.dll PCI I/O)
34 */
35
36 #include "vice.h"
37
38 #ifdef WIN32_COMPILE
39
40 #ifdef HAVE_CATWEASELMKIII
41 #include <windows.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <assert.h>
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #include "alarm.h"
51 #include "archdep.h"
52 #include "catweaselmkiii.h"
53 #include "cw-win32.h"
54 #include "log.h"
55 #include "sid-resources.h"
56 #include "types.h"
57 #include "wininpoutp.h"
58
59 #define CW_SID_DAT 0xd8
60 #define CW_SID_CMD 0xdc
61
62 #define MAXSID 1
63
64 static int sids_found = -1;
65 static int base = -1;
66
67 static int cw_use_lib = 0;
68
69 #ifndef MSVC_RC
70 typedef int _stdcall (*initfuncPtr)(void);
71 typedef void _stdcall (*shutdownfuncPtr)(void);
72 typedef int _stdcall (*inpfuncPtr)(WORD port, PDWORD value, BYTE size);
73 typedef int _stdcall (*oupfuncPtr)(WORD port, DWORD value, BYTE size);
74 #else
75 typedef int (CALLBACK* initfuncPtr)(void);
76 typedef void (CALLBACK* shutdownfuncPtr)(void);
77 typedef int (CALLBACK* inpfuncPtr)(WORD, PDWORD, BYTE);
78 typedef int (CALLBACK* oupfuncPtr)(WORD, DWORD, BYTE);
79 #endif
80
81 static initfuncPtr init32fp;
82 static shutdownfuncPtr shutdown32fp;
83 static inpfuncPtr inp32fp;
84 static oupfuncPtr oup32fp;
85
86
87 /* input/output functions */
cw_outb(unsigned int addrint,DWORD value)88 static void cw_outb(unsigned int addrint, DWORD value)
89 {
90 #ifdef _M_IX86
91 _outp(addrint, (BYTE)value);
92 #else
93 (void)addrint;
94 #endif
95 }
96
cw_outl(unsigned int addrint,DWORD value)97 static void cw_outl(unsigned int addrint, DWORD value)
98 {
99 #ifdef _M_IX86
100 _outpd(addrint, value);
101 #else
102 (void)addrint;
103 #endif
104 }
105
cw_inb(unsigned int addrint)106 static BYTE cw_inb(unsigned int addrint)
107 {
108 #ifdef _M_IX86
109 return _inp(addrint);
110 #else
111 (void)addrint;
112 return 0;
113 #endif
114 }
115
cw_inl(unsigned int addrint)116 static DWORD cw_inl(unsigned int addrint)
117 {
118 #ifdef _M_IX86
119 return _inpd(addrint);
120 #else
121 (void)addrint;
122 #endif
123 return 0;
124 }
125
cw_pci_read(uint16_t addr,int chipno)126 int cw_pci_read(uint16_t addr, int chipno)
127 {
128 unsigned char cmd;
129
130 if (chipno < MAXSID && base != -1 && addr < 0x20) {
131 cmd = (addr & 0x1f) | 0x20;
132 if (catweaselmkiii_get_ntsc()) {
133 cmd |= 0x40;
134 }
135 cw_outb(base + CW_SID_CMD, cmd);
136 archdep_usleep(1);
137 return cw_inb(base + CW_SID_DAT);
138 }
139 return 0;
140 }
141
cw_pci_store(uint16_t addr,uint8_t outval,int chipno)142 void cw_pci_store(uint16_t addr, uint8_t outval, int chipno)
143 {
144 unsigned char cmd;
145
146 if (chipno < MAXSID && base != -1 && addr < 0x20) {
147 cmd = addr & 0x1f;
148 if (catweaselmkiii_get_ntsc()) {
149 cmd |= 0x40;
150 }
151 cw_outb(base + CW_SID_DAT, outval);
152 cw_outb(base + CW_SID_CMD, cmd);
153 archdep_usleep(1);
154 }
155 }
156
157 /*----------------------------------------------------------------------*/
158
159 static HINSTANCE hLib = NULL;
160
161 /*
162 * Is this shit required? Doesn't MSYS2 take care of this?
163 */
164 #if defined(__amd64__) || defined(__x86_64__)
165 # define INPOUTDLLNAME "winio64.dll"
166 #else
167 # define INPOUTDLLNAME "winio32.dll"
168 # define INPOUTDLLOLDNAME "winio.dll"
169 #endif
170
detect_sid(void)171 static int detect_sid(void)
172 {
173 int i;
174
175 for (i = 0x18; i >= 0; --i) {
176 cw_pci_store((WORD)i, 0, 0);
177 }
178
179 cw_pci_store(0x12, 0xff, 0);
180
181 for (i = 0; i < 100; ++i) {
182 if (cw_pci_read(0x1b, 0)) {
183 return 0;
184 }
185 }
186
187 cw_pci_store(0x0e, 0xff, 0);
188 cw_pci_store(0x0f, 0xff, 0);
189 cw_pci_store(0x12, 0x20, 0);
190
191 for (i = 0; i < 100; ++i) {
192 if (cw_pci_read(0x1b, 0)) {
193 return 1;
194 }
195 }
196 return 0;
197 }
198
199 #ifndef KEY_WOW64_64KEY
200 #define KEY_WOW64_64KEY 0x0100
201 #endif
202
203 #ifndef KEY_WOW64_32KEY
204 #define KEY_WOW64_32KEY 0x0200
205 #endif
206
207 /* RegOpenKeyEx wrapper for smart access to both 32bit and 64bit registry entries */
RegOpenKeyEx3264(HKEY hKey,LPCTSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)208 static LONG RegOpenKeyEx3264(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
209 {
210 LONG retval = 0;
211
212 /* Check 64bit first */
213 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_64KEY, phkResult);
214
215 if (retval == ERROR_SUCCESS) {
216 return retval;
217 }
218
219 /* Check 32bit second */
220 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_32KEY, phkResult);
221
222 if (retval == ERROR_SUCCESS) {
223 return retval;
224 }
225
226 /* Fallback to normal open */
227 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);
228
229 return retval;
230 }
231
has_pci(void)232 static int has_pci(void)
233 {
234 HKEY hKey;
235 LONG ret;
236
237 if (archdep_is_windows_nt()) {
238 return 1;
239 }
240
241 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
242 if (ret == ERROR_SUCCESS) {
243 RegCloseKey(hKey);
244 return 1;
245 }
246
247 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
248 if (ret == ERROR_SUCCESS) {
249 RegCloseKey(hKey);
250 return 1;
251 }
252
253 return 0;
254 }
255
find_pci_device(int vendorID,int deviceID)256 static int find_pci_device(int vendorID, int deviceID)
257 {
258 int bus_index;
259 int slot_index;
260 int func_index;
261 unsigned int address;
262 unsigned int device;
263
264 for (bus_index = 0; bus_index < 256; ++bus_index) {
265 for (slot_index = 0; slot_index < 32; ++slot_index) {
266 for (func_index = 0; func_index < 8; ++func_index) {
267 address = 0x80000000 | (bus_index << 16) | (slot_index << 11) | (func_index << 8);
268 cw_outl(0xCF8, address);
269 device = cw_inl(0xCFC);
270 if (device == (unsigned int)(vendorID | (deviceID << 16))) {
271 address |= 0x10;
272 cw_outl(0xCF8, address);
273 base = cw_inl(0xCFC) & 0xFFFC;
274 return 0;
275 }
276 }
277 }
278 }
279 return -1;
280 }
281
close_device(void)282 static void close_device(void)
283 {
284 if (cw_use_lib) {
285 shutdown32fp();
286 FreeLibrary(hLib);
287 hLib = NULL;
288 }
289 }
290
cw_pci_open(void)291 int cw_pci_open(void)
292 {
293 int res;
294 char *openedlib = NULL;
295
296 if (!sids_found) {
297 return -1;
298 }
299
300 if (sids_found > 0) {
301 return 0;
302 }
303
304 sids_found = 0;
305
306 log_message(LOG_DEFAULT, "Detecting PCI CatWeasel boards.");
307
308 if (!has_pci()) {
309 log_message(LOG_DEFAULT, "No PCI bus present.");
310 return -1;
311 }
312
313 /* Only use dll when on win nt and up */
314 if (!(GetVersion() & 0x80000000) && cw_use_lib == 0) {
315
316 #ifdef INPOUTDLLOLDNAME
317 if (hLib == NULL) {
318 openedlib = INPOUTDLLOLDNAME;
319 hLib = LoadLibrary(INPOUTDLLOLDNAME);
320 }
321 #endif
322
323 if (hLib == NULL) {
324 hLib = LoadLibrary(INPOUTDLLNAME);
325 openedlib = INPOUTDLLNAME;
326 }
327 }
328
329 cw_use_lib = 0;
330
331 if (hLib != NULL) {
332 log_message(LOG_DEFAULT, "Opened %s.", openedlib);
333
334 inp32fp = (inpfuncPtr)GetProcAddress(hLib, "GetPortVal");
335 if (inp32fp != NULL) {
336 oup32fp = (oupfuncPtr)GetProcAddress(hLib, "SetPortVal");
337 if (oup32fp != NULL) {
338 init32fp = (initfuncPtr)GetProcAddress(hLib, "InitializeWinIo");
339 if (init32fp != NULL) {
340 shutdown32fp = (shutdownfuncPtr)GetProcAddress(hLib, "ShutdownWinIo");
341 if (shutdown32fp != NULL) {
342 if (init32fp()) {
343 cw_use_lib = 1;
344 log_message(LOG_DEFAULT, "Using %s for PCI I/O access.", openedlib);
345 } else {
346 log_message(LOG_DEFAULT, "init call failed in %s.", openedlib);
347 }
348 } else {
349 log_message(LOG_DEFAULT, "Cannot get 'ShutdownWinIo' function from %s.", openedlib);
350 }
351 } else {
352 log_message(LOG_DEFAULT, "Cannot get 'InitializeWinIo' function from %s.", openedlib);
353 }
354 } else {
355 log_message(LOG_DEFAULT, "Cannot get 'SetPortVal' function from %s.", openedlib);
356 }
357 } else {
358 log_message(LOG_DEFAULT, "Cannot get 'GetPortVal' function from %s.", openedlib);
359 }
360 if (!cw_use_lib) {
361 log_message(LOG_DEFAULT, "Cannot get I/O functions in %s, using direct PCI I/O access.", openedlib);
362 }
363 } else {
364 log_message(LOG_DEFAULT, "Cannot open %s, trying direct PCI I/O access.", openedlib);
365 }
366
367
368 if (!(GetVersion() & 0x80000000) && cw_use_lib == 0) {
369 log_message(LOG_DEFAULT, "Cannot use direct PCI I/O access on Windows NT/2000/Server/XP/Vista/7/8/10.");
370 return -1;
371 }
372
373 res = find_pci_device(0xe159, 0x0001);
374
375 if (res < 0) {
376 log_message(LOG_DEFAULT, "No PCI CatWeasel found.");
377 close_device();
378 return -1;
379 }
380
381 log_message(LOG_DEFAULT, "PCI CatWeasel board found at $%04X.",
382 (unsigned int)base);
383
384 if (detect_sid()) {
385 sids_found++;
386 }
387
388 if (!sids_found) {
389 log_message(LOG_DEFAULT, "No PCI CatWeasel found.");
390 close_device();
391 return -1;
392 }
393
394 log_message(LOG_DEFAULT, "PCI CatWeasel: opened, found %d SIDs.", sids_found);
395
396 return 0;
397 }
398
cw_pci_close(void)399 int cw_pci_close(void)
400 {
401 close_device();
402
403 base = -1;
404
405 sids_found = -1;
406
407 log_message(LOG_DEFAULT, "PCI CatWeasel: closed");
408
409 return 0;
410 }
411
cw_pci_available(void)412 int cw_pci_available(void)
413 {
414 return sids_found;
415 }
416 #endif
417 #endif
418