1 /*
2 * cw-win32-pci.c - Windows specific PCI cw3 driver.
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 PCI I/O)
30 - Windows 98SE (Direct PCI I/O)
31 - Windows ME (Direct PCI I/O)
32 - Windows NT 4 (winio32.dll PCI I/O)
33 - Windows 2000 (winio32.dll PCI I/O)
34 - Windows XP (winio32.dll PCI I/O)
35 */
36
37 #include "vice.h"
38
39 #ifdef WIN32_COMPILE
40
41 #ifdef HAVE_CATWEASELMKIII
42 #include <windows.h>
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <assert.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include "alarm.h"
52 #include "archdep.h"
53 #include "catweaselmkiii.h"
54 #include "cw-win32.h"
55 #include "log.h"
56 #include "sid-resources.h"
57 #include "types.h"
58 #include "wininpoutp.h"
59
60 #define CW_SID_DAT 0xd8
61 #define CW_SID_CMD 0xdc
62
63 #define MAXSID 1
64
65 static int sids_found = -1;
66 static int base = -1;
67
68 static int cw_use_lib = 0;
69
70 #ifndef MSVC_RC
71 typedef int _stdcall (*initfuncPtr)(void);
72 typedef void _stdcall (*shutdownfuncPtr)(void);
73 typedef int _stdcall (*inpfuncPtr)(WORD port, PDWORD value, BYTE size);
74 typedef int _stdcall (*oupfuncPtr)(WORD port, DWORD value, BYTE size);
75 #else
76 typedef int (CALLBACK* initfuncPtr)(void);
77 typedef void (CALLBACK* shutdownfuncPtr)(void);
78 typedef int (CALLBACK* inpfuncPtr)(WORD, PDWORD, BYTE);
79 typedef int (CALLBACK* oupfuncPtr)(WORD, DWORD, BYTE);
80 #endif
81
82 static initfuncPtr init32fp;
83 static shutdownfuncPtr shutdown32fp;
84 static inpfuncPtr inp32fp;
85 static oupfuncPtr oup32fp;
86
87 /* input/output functions */
cw_outb(unsigned int addrint,DWORD value)88 static void cw_outb(unsigned int addrint, DWORD value)
89 {
90 WORD addr = (WORD)addrint;
91
92 /* make sure the above conversion did not loose any details */
93 assert(addr == addrint);
94
95 #ifdef _M_IX86
96 #ifdef WATCOM_COMPILE
97 outp(addr, (BYTE)value);
98 #else
99 _outp(addr, (BYTE)value);
100 #endif
101 #endif
102 }
103
cw_outl(unsigned int addrint,DWORD value)104 static void cw_outl(unsigned int addrint, DWORD value)
105 {
106 WORD addr = (WORD)addrint;
107
108 /* make sure the above conversion did not loose any details */
109 assert(addr == addrint);
110
111 #ifdef _M_IX86
112 #ifdef WATCOM_COMPILE
113 outpd(addr, value);
114 #else
115 _outpd(addr, value);
116 #endif
117 #endif
118 }
119
cw_inb(unsigned int addrint)120 static BYTE cw_inb(unsigned int addrint)
121 {
122 WORD addr = (WORD)addrint;
123
124 /* make sure the above conversion did not loose any details */
125 assert(addr == addrint);
126
127 #ifdef _M_IX86
128 #ifdef WATCOM_COMPILE
129 return inp(addr);
130 #else
131 return _inp(addr);
132 #endif
133 #endif
134 return 0;
135 }
136
cw_inl(unsigned int addrint)137 static DWORD cw_inl(unsigned int addrint)
138 {
139 WORD addr = (WORD)addrint;
140
141 /* make sure the above conversion did not loose any details */
142 assert(addr == addrint);
143
144 #ifdef _M_IX86
145 #ifdef WATCOM_COMPILE
146 return inpd(addr);
147 #else
148 return _inpd(addr);
149 #endif
150 #endif
151 return 0;
152 }
153
cw_pci_read(uint16_t addr,int chipno)154 int cw_pci_read(uint16_t addr, int chipno)
155 {
156 unsigned char cmd;
157
158 if (chipno < MAXSID && base != -1 && addr < 0x20) {
159 cmd = (addr & 0x1f) | 0x20;
160 if (catweaselmkiii_get_ntsc()) {
161 cmd |= 0x40;
162 }
163 cw_outb(base + CW_SID_CMD, cmd);
164 vice_usleep(1);
165 return cw_inb(base + CW_SID_DAT);
166 }
167 return 0;
168 }
169
cw_pci_store(uint16_t addr,uint8_t outval,int chipno)170 void cw_pci_store(uint16_t addr, uint8_t outval, int chipno)
171 {
172 unsigned char cmd;
173
174 if (chipno < MAXSID && base != -1 && addr < 0x20) {
175 cmd = addr & 0x1f;
176 if (catweaselmkiii_get_ntsc()) {
177 cmd |= 0x40;
178 }
179 cw_outb(base + CW_SID_DAT, outval);
180 cw_outb(base + CW_SID_CMD, cmd);
181 vice_usleep(1);
182 }
183 }
184
185 /*----------------------------------------------------------------------*/
186
187 static HINSTANCE hLib = NULL;
188
189 #ifdef _MSC_VER
190 # ifdef _WIN64
191 # define INPOUTDLLNAME "winio64.dll"
192 # else
193 # define INPOUTDLLNAME "winio32.dll"
194 # define INPOUTDLLOLDNAME "winio.dll"
195 # endif
196 #else
197 # if defined(__amd64__) || defined(__x86_64__)
198 # define INPOUTDLLNAME "winio64.dll"
199 # else
200 # define INPOUTDLLNAME "winio32.dll"
201 # define INPOUTDLLOLDNAME "winio.dll"
202 # endif
203 #endif
204
detect_sid(void)205 static int detect_sid(void)
206 {
207 int i;
208
209 for (i = 0x18; i >= 0; --i) {
210 cw_pci_store((WORD)i, 0, 0);
211 }
212
213 cw_pci_store(0x12, 0xff, 0);
214
215 for (i = 0; i < 100; ++i) {
216 if (cw_pci_read(0x1b, 0)) {
217 return 0;
218 }
219 }
220
221 cw_pci_store(0x0e, 0xff, 0);
222 cw_pci_store(0x0f, 0xff, 0);
223 cw_pci_store(0x12, 0x20, 0);
224
225 for (i = 0; i < 100; ++i) {
226 if (cw_pci_read(0x1b, 0)) {
227 return 1;
228 }
229 }
230 return 0;
231 }
232
233 #ifndef KEY_WOW64_64KEY
234 #define KEY_WOW64_64KEY 0x0100
235 #endif
236
237 #ifndef KEY_WOW64_32KEY
238 #define KEY_WOW64_32KEY 0x0200
239 #endif
240
241 /* RegOpenKeyEx wrapper for smart access to both 32bit and 64bit registry entries */
RegOpenKeyEx3264(HKEY hKey,LPCTSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)242 static LONG RegOpenKeyEx3264(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
243 {
244 LONG retval = 0;
245
246 /* Check 64bit first */
247 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_64KEY, phkResult);
248
249 if (retval == ERROR_SUCCESS) {
250 return retval;
251 }
252
253 /* Check 32bit second */
254 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_32KEY, phkResult);
255
256 if (retval == ERROR_SUCCESS) {
257 return retval;
258 }
259
260 /* Fallback to normal open */
261 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);
262
263 return retval;
264 }
265
has_pci(void)266 static int has_pci(void)
267 {
268 HKEY hKey;
269 LONG ret;
270
271 if (is_windows_nt()) {
272 return 1;
273 }
274
275 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
276 if (ret == ERROR_SUCCESS) {
277 RegCloseKey(hKey);
278 return 1;
279 }
280
281 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
282 if (ret == ERROR_SUCCESS) {
283 RegCloseKey(hKey);
284 return 1;
285 }
286
287 return 0;
288 }
289
find_pci_device(int vendorID,int deviceID)290 static int find_pci_device(int vendorID, int deviceID)
291 {
292 int bus_index;
293 int slot_index;
294 int func_index;
295 unsigned int address;
296 unsigned int device;
297
298 for (bus_index = 0; bus_index < 256; ++bus_index) {
299 for (slot_index = 0; slot_index < 32; ++slot_index) {
300 for (func_index = 0; func_index < 8; ++func_index) {
301 address = 0x80000000 | (bus_index << 16) | (slot_index << 11) | (func_index << 8);
302 cw_outl(0xCF8, address);
303 device = cw_inl(0xCFC);
304 if (device == (unsigned int)(vendorID | (deviceID << 16))) {
305 address |= 0x10;
306 cw_outl(0xCF8, address);
307 base = cw_inl(0xCFC) & 0xFFFC;
308 return 0;
309 }
310 }
311 }
312 }
313 return -1;
314 }
315
close_device(void)316 static void close_device(void)
317 {
318 if (cw_use_lib) {
319 shutdown32fp();
320 FreeLibrary(hLib);
321 hLib = NULL;
322 }
323 }
324
cw_pci_open(void)325 int cw_pci_open(void)
326 {
327 int res;
328 char *openedlib = NULL;
329
330 if (!sids_found) {
331 return -1;
332 }
333
334 if (sids_found > 0) {
335 return 0;
336 }
337
338 sids_found = 0;
339
340 log_message(LOG_DEFAULT, "Detecting PCI CatWeasel boards.");
341
342 if (!has_pci()) {
343 log_message(LOG_DEFAULT, "No PCI bus present.");
344 return -1;
345 }
346
347 /* Only use dll when on win nt and up */
348 if (!(GetVersion() & 0x80000000) && cw_use_lib == 0) {
349
350 #ifdef INPOUTDLLOLDNAME
351 if (hLib == NULL) {
352 openedlib = INPOUTDLLOLDNAME;
353 hLib = LoadLibrary(INPOUTDLLOLDNAME);
354 }
355 #endif
356
357 if (hLib == NULL) {
358 hLib = LoadLibrary(INPOUTDLLNAME);
359 openedlib = INPOUTDLLNAME;
360 }
361 }
362
363 cw_use_lib = 0;
364
365 if (hLib != NULL) {
366 log_message(LOG_DEFAULT, "Opened %s.", openedlib);
367
368 inp32fp = (inpfuncPtr)GetProcAddress(hLib, "GetPortVal");
369 if (inp32fp != NULL) {
370 oup32fp = (oupfuncPtr)GetProcAddress(hLib, "SetPortVal");
371 if (oup32fp != NULL) {
372 init32fp = (initfuncPtr)GetProcAddress(hLib, "InitializeWinIo");
373 if (init32fp != NULL) {
374 shutdown32fp = (shutdownfuncPtr)GetProcAddress(hLib, "ShutdownWinIo");
375 if (shutdown32fp != NULL) {
376 if (init32fp()) {
377 cw_use_lib = 1;
378 log_message(LOG_DEFAULT, "Using %s for PCI I/O access.", openedlib);
379 } else {
380 log_message(LOG_DEFAULT, "init call failed in %s.", openedlib);
381 }
382 } else {
383 log_message(LOG_DEFAULT, "Cannot get 'ShutdownWinIo' function from %s.", openedlib);
384 }
385 } else {
386 log_message(LOG_DEFAULT, "Cannot get 'InitializeWinIo' function from %s.", openedlib);
387 }
388 } else {
389 log_message(LOG_DEFAULT, "Cannot get 'SetPortVal' function from %s.", openedlib);
390 }
391 } else {
392 log_message(LOG_DEFAULT, "Cannot get 'GetPortVal' function from %s.", openedlib);
393 }
394 if (!cw_use_lib) {
395 log_message(LOG_DEFAULT, "Cannot get I/O functions in %s, using direct PCI I/O access.", openedlib);
396 }
397 } else {
398 log_message(LOG_DEFAULT, "Cannot open %s, trying direct PCI I/O access.", openedlib);
399 }
400
401
402 if (!(GetVersion() & 0x80000000) && cw_use_lib == 0) {
403 log_message(LOG_DEFAULT, "Cannot use direct PCI I/O access on Windows NT/2000/Server/XP/Vista/7/8/10.");
404 return -1;
405 }
406
407 res = find_pci_device(0xe159, 0x0001);
408
409 if (res < 0) {
410 log_message(LOG_DEFAULT, "No PCI CatWeasel found.");
411 close_device();
412 return -1;
413 }
414
415 log_message(LOG_DEFAULT, "PCI CatWeasel board found at $%04X.", base);
416
417 if (detect_sid()) {
418 sids_found++;
419 }
420
421 if (!sids_found) {
422 log_message(LOG_DEFAULT, "No PCI CatWeasel found.");
423 close_device();
424 return -1;
425 }
426
427 log_message(LOG_DEFAULT, "PCI CatWeasel: opened, found %d SIDs.", sids_found);
428
429 return 0;
430 }
431
cw_pci_close(void)432 int cw_pci_close(void)
433 {
434 close_device();
435
436 base = -1;
437
438 sids_found = -1;
439
440 log_message(LOG_DEFAULT, "PCI CatWeasel: closed");
441
442 return 0;
443 }
444
cw_pci_available(void)445 int cw_pci_available(void)
446 {
447 return sids_found;
448 }
449 #endif
450 #endif
451