1 /*
2 * hs-win32-pci.c - HardSID PCI 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 (PCI HardSID, Direct PCI I/O)
30 - Windows 95C (PCI HardSID Quattro, Direct PCI I/O)
31 - Windows 98SE (PCI HardSID, Direct PCI I/O)
32 - Windows 98SE (PCI HardSID Quattro, Direct PCI I/O)
33 - Windows ME (PCI HardSID, Direct PCI I/O)
34 - Windows ME (PCI HardSID Quattro, Direct PCI I/O)
35 - Windows NT 4 (PCI HardSID, winio32.dll PCI I/O)
36 - Windows NT 4 (PCI HardSID Quattro, winio32.dll PCI I/O)
37 - Windows 2000 (PCI HardSID, winio32.dll PCI I/O)
38 - Windows 2000 (PCI HardSID Quattro, winio32.dll PCI I/O)
39 - Windows XP (PCI HardSID, winio32.dll PCI I/O)
40 - Windows XP (PCI HardSID Quattro, winio32.dll PCI I/O)
41 - Windows 2003 Server (PCI HardSID, winio32.dll PCI I/O)
42 - Windows 2003 Server (PCI HardSID Quattro, winio32.dll PCI I/O)
43 */
44
45 #include "vice.h"
46
47 #ifdef WIN32_COMPILE
48
49 #ifdef HAVE_HARDSID
50 #include <windows.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <assert.h>
54
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 #include "alarm.h"
60 #include "archdep.h"
61 #include "hardsid.h"
62 #include "hs-win32.h"
63 #include "log.h"
64 #include "sid-resources.h"
65 #include "types.h"
66 #include "wininpoutp.h"
67
68 #define MAXSID 4
69
70 static int sids_found = -1;
71 static int hssids[MAXSID] = {-1, -1, -1, -1};
72
73 static int io1 = 0;
74 static int io2 = 0;
75
76 static int hardsid_use_lib = 0;
77
78 #ifndef MSVC_RC
79 typedef int _stdcall (*initfuncPtr)(void);
80 typedef void _stdcall (*shutdownfuncPtr)(void);
81 typedef int _stdcall (*inpfuncPtr)(WORD port, PDWORD value, BYTE size);
82 typedef int _stdcall (*oupfuncPtr)(WORD port, DWORD value, BYTE size);
83 #else
84 typedef int (CALLBACK* initfuncPtr)(void);
85 typedef void (CALLBACK* shutdownfuncPtr)(void);
86 typedef int (CALLBACK* inpfuncPtr)(WORD, PDWORD, BYTE);
87 typedef int (CALLBACK* oupfuncPtr)(WORD, DWORD, BYTE);
88 #endif
89
90 static initfuncPtr init32fp;
91 static shutdownfuncPtr shutdown32fp;
92 static inpfuncPtr inp32fp;
93 static oupfuncPtr oup32fp;
94
95 /* input/output functions */
hardsid_outb(unsigned int addrint,DWORD value)96 static void hardsid_outb(unsigned int addrint, DWORD value)
97 {
98 WORD addr = (WORD)addrint;
99
100 /* make sure the above conversion did not loose any details */
101 assert(addr == addrint);
102
103 #ifdef _M_IX86
104 #ifdef WATCOM_COMPILE
105 outp(addr, (BYTE)value);
106 #else
107 _outp(addr, (BYTE)value);
108 #endif
109 #endif
110 }
111
hardsid_outl(unsigned int addrint,DWORD value)112 static void hardsid_outl(unsigned int addrint, DWORD value)
113 {
114 WORD addr = (WORD)addrint;
115
116 /* make sure the above conversion did not loose any details */
117 assert(addr == addrint);
118
119 #ifdef _M_IX86
120 #ifdef WATCOM_COMPILE
121 outpd(addr, value);
122 #else
123 _outpd(addr, value);
124 #endif
125 #endif
126 }
127
hardsid_inb(unsigned int addrint)128 static BYTE hardsid_inb(unsigned int addrint)
129 {
130 WORD addr = (WORD)addrint;
131
132 /* make sure the above conversion did not loose any details */
133 assert(addr == addrint);
134
135 #ifdef _M_IX86
136 #ifdef WATCOM_COMPILE
137 return inp(addr);
138 #else
139 return _inp(addr);
140 #endif
141 #endif
142 return 0;
143 }
144
hardsid_inl(unsigned int addrint)145 static DWORD hardsid_inl(unsigned int addrint)
146 {
147 WORD addr = (WORD)addrint;
148
149 /* make sure the above conversion did not loose any details */
150 assert(addr == addrint);
151
152 #ifdef _M_IX86
153 #ifdef WATCOM_COMPILE
154 return inpd(addr);
155 #else
156 return _inpd(addr);
157 #endif
158 #endif
159 return 0;
160 }
161
hs_pci_read(uint16_t addr,int chipno)162 int hs_pci_read(uint16_t addr, int chipno)
163 {
164 uint8_t ret = 0;
165
166 if (chipno < MAXSID && hssids[chipno] != -1 && addr < 0x20) {
167 hardsid_outb(io1 + 4, (BYTE)((chipno << 6) | (addr & 0x1f) | 0x20));
168 vice_usleep(2);
169 hardsid_outb(io2 + 2, 0x20);
170 ret = hardsid_inb(io1);
171 hardsid_outb(io2 + 2, 0x80);
172 }
173 return ret;
174 }
175
hs_pci_store(uint16_t addr,uint8_t outval,int chipno)176 void hs_pci_store(uint16_t addr, uint8_t outval, int chipno)
177 {
178 if (chipno < MAXSID && hssids[chipno] != -1 && addr < 0x20) {
179 hardsid_outb(io1 + 3, outval);
180 hardsid_outb(io1 + 4, (BYTE)((chipno << 6) | (addr & 0x1f)));
181 vice_usleep(2);
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_uno(void)205 static int detect_sid_uno(void)
206 {
207 int i;
208 int j;
209
210 for (j = 0; j < 4; ++j) {
211 for (i = 0x18; i >= 0; --i) {
212 hs_pci_store((WORD)i, 0, j);
213 }
214 }
215
216 hs_pci_store(0x12, 0xff, 0);
217
218 for (i = 0; i < 100; ++i) {
219 if (hs_pci_read(0x1b, 3)) {
220 return 0;
221 }
222 }
223
224 hs_pci_store(0x0e, 0xff, 0);
225 hs_pci_store(0x0f, 0xff, 0);
226 hs_pci_store(0x12, 0x20, 0);
227
228 for (i = 0; i < 100; ++i) {
229 if (hs_pci_read(0x1b, 3)) {
230 return 1;
231 }
232 }
233 return 0;
234 }
235
detect_sid(int chipno)236 static int detect_sid(int chipno)
237 {
238 int i;
239
240 for (i = 0x18; i >= 0; --i) {
241 hs_pci_store((WORD)i, 0, chipno);
242 }
243
244 hs_pci_store(0x12, 0xff, chipno);
245
246 for (i = 0; i < 100; ++i) {
247 if (hs_pci_read(0x1b, chipno)) {
248 return 0;
249 }
250 }
251
252 hs_pci_store(0x0e, 0xff, chipno);
253 hs_pci_store(0x0f, 0xff, chipno);
254 hs_pci_store(0x12, 0x20, chipno);
255
256 for (i = 0; i < 100; ++i) {
257 if (hs_pci_read(0x1b, chipno)) {
258 return 1;
259 }
260 }
261 return 0;
262 }
263
264 #ifndef KEY_WOW64_64KEY
265 #define KEY_WOW64_64KEY 0x0100
266 #endif
267
268 #ifndef KEY_WOW64_32KEY
269 #define KEY_WOW64_32KEY 0x0200
270 #endif
271
272 /* RegOpenKeyEx wrapper for smart access to both 32bit and 64bit registry entries */
RegOpenKeyEx3264(HKEY hKey,LPCTSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)273 static LONG RegOpenKeyEx3264(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
274 {
275 LONG retval = 0;
276
277 /* Check 64bit first */
278 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_64KEY, phkResult);
279
280 if (retval == ERROR_SUCCESS) {
281 return retval;
282 }
283
284 /* Check 32bit second */
285 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired | KEY_WOW64_32KEY, phkResult);
286
287 if (retval == ERROR_SUCCESS) {
288 return retval;
289 }
290
291 /* Fallback to normal open */
292 retval = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);
293
294 return retval;
295 }
296
has_pci(void)297 static int has_pci(void)
298 {
299 HKEY hKey;
300 LONG ret;
301
302 if (is_windows_nt()) {
303 return 1;
304 }
305
306 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
307 if (ret == ERROR_SUCCESS) {
308 RegCloseKey(hKey);
309 return 1;
310 }
311
312 ret = RegOpenKeyEx3264(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, KEY_QUERY_VALUE, &hKey);
313 if (ret == ERROR_SUCCESS) {
314 RegCloseKey(hKey);
315 return 1;
316 }
317
318 return 0;
319 }
320
find_pci_device(int vendorID,int deviceID)321 static int find_pci_device(int vendorID, int deviceID)
322 {
323 int bus_index;
324 int slot_index;
325 int func_index;
326 unsigned int address;
327 unsigned int device;
328
329 for (bus_index = 0; bus_index < 256; ++bus_index) {
330 for (slot_index = 0; slot_index < 32; ++slot_index) {
331 for (func_index = 0; func_index < 8; ++func_index) {
332 address = 0x80000000 | (bus_index << 16) | (slot_index << 11) | (func_index << 8);
333 hardsid_outl(0xCF8, address);
334 device = hardsid_inl(0xCFC);
335 if (device == (unsigned int)(vendorID | (deviceID << 16))) {
336 address |= 0x10;
337 hardsid_outl(0xCF8, address);
338 io1 = hardsid_inl(0xCFC) & 0xFFFC;
339 address |= 0x04;
340 hardsid_outl(0xCF8, address);
341 io2 = hardsid_inl(0xCFC) & 0xFFFC;
342 return 0;
343 }
344 }
345 }
346 }
347 return -1;
348 }
349
close_device(void)350 static void close_device(void)
351 {
352 if (hardsid_use_lib) {
353 shutdown32fp();
354 FreeLibrary(hLib);
355 hLib = NULL;
356 }
357 }
358
hs_pci_open(void)359 int hs_pci_open(void)
360 {
361 int i;
362 int res;
363 char *openedlib = NULL;
364
365 if (!sids_found) {
366 return -1;
367 }
368
369 if (sids_found > 0) {
370 return 0;
371 }
372
373 sids_found = 0;
374
375 log_message(LOG_DEFAULT, "Detecting PCI HardSID boards.");
376
377 if (!has_pci()) {
378 log_message(LOG_DEFAULT, "No PCI bus present.");
379 return -1;
380 }
381
382 hardsid_use_lib = 0;
383
384 /* Only use dll when on win nt and up */
385 if (!(GetVersion() & 0x80000000) && hardsid_use_lib == 0) {
386
387 #ifdef INPOUTDLLOLDNAME
388 if (hLib == NULL) {
389 openedlib = INPOUTDLLOLDNAME;
390 hLib = LoadLibrary(INPOUTDLLOLDNAME);
391 }
392 #endif
393
394 if (hLib == NULL) {
395 hLib = LoadLibrary(INPOUTDLLNAME);
396 openedlib = INPOUTDLLNAME;
397 }
398
399 if (hLib != NULL) {
400 log_message(LOG_DEFAULT, "Opened %s.", openedlib);
401
402 inp32fp = (inpfuncPtr)GetProcAddress(hLib, "GetPortVal");
403 if (inp32fp != NULL) {
404 oup32fp = (oupfuncPtr)GetProcAddress(hLib, "SetPortVal");
405 if (oup32fp != NULL) {
406 init32fp = (initfuncPtr)GetProcAddress(hLib, "InitializeWinIo");
407 if (init32fp != NULL) {
408 shutdown32fp = (shutdownfuncPtr)GetProcAddress(hLib, "ShutdownWinIo");
409 if (shutdown32fp != NULL) {
410 if (init32fp()) {
411 hardsid_use_lib = 1;
412 log_message(LOG_DEFAULT, "Using %s for PCI I/O access.", openedlib);
413 } else {
414 log_message(LOG_DEFAULT, "Cannot init %s.", openedlib);
415 }
416 } else {
417 log_message(LOG_DEFAULT, "Cannot get 'ShutdownWinIo' function from %s.", openedlib);
418 }
419 } else {
420 log_message(LOG_DEFAULT, "Cannot get 'InitializeWinIo' function from %s.", openedlib);
421 }
422 } else {
423 log_message(LOG_DEFAULT, "Cannot get 'SetPortVal' function from %s.", openedlib);
424 }
425 } else {
426 log_message(LOG_DEFAULT, "Cannot get 'GetPortVal' function from %s.", openedlib);
427 }
428 if (!hardsid_use_lib) {
429 log_message(LOG_DEFAULT, "Cannot get I/O functions in %s, using direct PCI I/O access.", openedlib);
430 }
431 } else {
432 log_message(LOG_DEFAULT, "Cannot open %s, trying direct PCI I/O access.", openedlib);
433 }
434 } else {
435 log_message(LOG_DEFAULT, "Using direct PCI I/O access.");
436 }
437
438 if (!(GetVersion() & 0x80000000) && hardsid_use_lib == 0) {
439 log_message(LOG_DEFAULT, "Cannot use direct PCI I/O access on Windows NT/2000/Server/XP/Vista/7/8/10.");
440 return -1;
441 }
442
443 res = find_pci_device(0x6581, 0x8580);
444
445 if (res < 0) {
446 log_message(LOG_DEFAULT, "No PCI HardSID found.");
447 close_device();
448 return -1;
449 }
450
451 log_message(LOG_DEFAULT, "PCI HardSID board found at $%04X and $%04X", io1, io2);
452
453 for (i = 0; i < MAXSID; ++i) {
454 hssids[sids_found] = i;
455 if (detect_sid(i)) {
456 sids_found++;
457 }
458 }
459
460 if (!sids_found) {
461 log_message(LOG_DEFAULT, "No PCI HardSID found.");
462 close_device();
463 return -1;
464 }
465
466 /* Check for classic HardSID if 4 SIDs were found. */
467 if (sids_found == 4) {
468 if (detect_sid_uno()) {
469 sids_found = 1;
470 }
471 }
472
473 log_message(LOG_DEFAULT, "PCI HardSID: opened, found %d SIDs.", sids_found);
474
475 return 0;
476 }
477
hs_pci_close(void)478 int hs_pci_close(void)
479 {
480 int i;
481
482 close_device();
483
484 for (i = 0; i < MAXSID; ++i) {
485 if (hssids[i] != -1) {
486 hssids[i] = -1;
487 }
488 }
489
490 sids_found = -1;
491
492 log_message(LOG_DEFAULT, "PCI HardSID: closed");
493
494 return 0;
495 }
496
hs_pci_available(void)497 int hs_pci_available(void)
498 {
499 return sids_found;
500 }
501
502 /* ---------------------------------------------------------------------*/
503
hs_pci_state_read(int chipno,struct sid_hs_snapshot_state_s * sid_state)504 void hs_pci_state_read(int chipno, struct sid_hs_snapshot_state_s *sid_state)
505 {
506 sid_state->hsid_main_clk = 0;
507 sid_state->hsid_alarm_clk = 0;
508 sid_state->lastaccess_clk = 0;
509 sid_state->lastaccess_ms = 0;
510 sid_state->lastaccess_chipno = 0;
511 sid_state->chipused = 0;
512 sid_state->device_map[0] = 0;
513 sid_state->device_map[1] = 0;
514 sid_state->device_map[2] = 0;
515 sid_state->device_map[3] = 0;
516 }
517
hs_pci_state_write(int chipno,struct sid_hs_snapshot_state_s * sid_state)518 void hs_pci_state_write(int chipno, struct sid_hs_snapshot_state_s *sid_state)
519 {
520 }
521 #endif
522 #endif
523
524