1 /*
2 * hs-amiga-os4.c - AmigaOS 4.x specific PCI hardsid 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 #include "vice.h"
28
29 #ifdef AMIGA_SUPPORT
30
31 #if defined(HAVE_HARDSID) && defined(AMIGA_OS4)
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "hardsid.h"
38 #include "hs-amiga.h"
39
40 #if !defined(USE_SDLUI) && !defined(USE_SDLUI2)
41 # include "loadlibs.h"
42 #else
43 # include "archdep.h"
44 #endif
45
46 #include "log.h"
47 #include "types.h"
48
49
50 static unsigned char read_sid(unsigned char reg, int chipno); /* Read a SID register */
51 static void write_sid(unsigned char reg, unsigned char data, int chipno); /* Write a SID register */
52
53 #define MAXSID 4
54
55 static int sids_found = -1;
56
57 static int hssids[MAXSID] = {-1, -1, -1, -1};
58
59 /* read value from SIDs */
hs_os4_read(uint16_t addr,int chipno)60 int hs_os4_read(uint16_t addr, int chipno)
61 {
62 /* check if chipno and addr is valid */
63 if (chipno < MAXSID && hssids[chipno] != -1 && addr < 0x20) {
64 return read_sid(addr, hssids[chipno]);
65 }
66 return 0;
67 }
68
69 /* write value into SID */
hs_os4_store(uint16_t addr,uint8_t val,int chipno)70 void hs_os4_store(uint16_t addr, uint8_t val, int chipno)
71 {
72 /* check if chipno and addr is valid */
73 if (chipno < MAXSID && hssids[chipno] != -1 && addr < 0x20) {
74 write_sid(addr, val, hssids[chipno]);
75 }
76 }
77
78 #undef BYTE
79 #undef WORD
80 #include <exec/types.h>
81 #include <proto/expansion.h>
82 #include <proto/exec.h>
83
84 static struct PCIIFace *IPCI = NULL;
85
86 static struct PCIDevice *HSDevPCI = NULL;
87 static struct PCIResourceRange *HSDevBAR = NULL;
88 int HSLock = FALSE;
89
detect_sid(int chipno)90 static int detect_sid(int chipno)
91 {
92 int i;
93
94 for (i = 0x18; i >= 0; --i) {
95 write_sid((unsigned short)i, 0, chipno);
96 }
97
98 write_sid(0x12, 0xff, chipno);
99
100 for (i = 0; i < 100; ++i) {
101 if (read_sid(0x1b, chipno)) {
102 return 0;
103 }
104 }
105
106 write_sid(0x0e, 0xff, chipno);
107 write_sid(0x0f, 0xff, chipno);
108 write_sid(0x12, 0x20, chipno);
109
110 for (i = 0; i < 100; ++i) {
111 if (read_sid(0x1b, chipno)) {
112 return 1;
113 }
114 }
115 return 0;
116 }
117
close_device(void)118 static void close_device(void)
119 {
120 if (HSDevBAR) {
121 HSDevPCI->FreeResourceRange(HSDevBAR);
122 }
123 if (HSLock) {
124 HSDevPCI->Unlock();
125 }
126 if (IPCI) {
127 IExec->DropInterface((struct Interface *)IPCI);
128 }
129 }
130
hs_os4_open(void)131 int hs_os4_open(void)
132 {
133 unsigned int i, j;
134
135 if (!sids_found) {
136 return -1;
137 }
138
139 if (sids_found > 0) {
140 return 0;
141 }
142
143 sids_found = 0;
144
145 log_message(LOG_DEFAULT, "Detecting PCI HardSID boards.");
146
147 if (!pci_lib_loaded) {
148 log_message(LOG_DEFAULT, "Expansion library not available.");
149 return -1;
150 }
151
152 IPCI = (struct PCIIFace *)IExec->GetInterface(ExpansionBase, "pci", 1, NULL);
153 if (!IPCI) {
154 log_message(LOG_DEFAULT, "Unable to obtain PCI expansion interface.");
155 return -1;
156 }
157
158 /* Try and find a HS on the PCI bus */
159 HSDevPCI = IPCI->FindDeviceTags(FDT_VendorID, 0x6581,
160 FDT_DeviceID, 0x8580,
161 FDT_Index, 0,
162 TAG_DONE);
163 if (!HSDevPCI) {
164 log_message(LOG_DEFAULT, "Unable to find a PCI HardSID board.");
165 close_device();
166 return -1;
167 }
168
169 /* Lock the device, since we're a driver */
170 HSLock = HSDevPCI->Lock(PCI_LOCK_SHARED);
171 if (!HSLock) {
172 log_message(LOG_DEFAULT, "Unable to lock the PCI HardSID. Another driver may have an exclusive lock.");
173 close_device();
174 return -1;
175 }
176
177 /* Get the resource range */
178 HSDevBAR = HSDevPCI->GetResourceRange(0);
179 if (!HSDevBAR) {
180 log_message(LOG_DEFAULT, "Unable to get PCI HardSID resource range 0.");
181 close_device();
182 return -1;
183 }
184
185 /* Reset the hardsid PCI interface (as per hardsid linux driver) */
186 HSDevPCI->OutByte(HSDevBAR->BaseAddress + 0x00, 0xff);
187 HSDevPCI->OutByte(HSDevBAR->BaseAddress + 0x02, 0xff);
188 usleep(100);
189 HSDevPCI->OutByte(HSDevBAR->BaseAddress + 0x02, 0x24);
190
191 for (j = 0; j < MAXSID; ++j) {
192 if (detect_sid(j)) {
193 hssids[sids_found] = j;
194 sids_found++;
195 }
196 }
197
198 if (!sids_found) {
199 log_message(LOG_DEFAULT, "No PCI HardSID boards found.");
200 close_device();
201 return -1;
202 }
203
204 /* mute all sids */
205 for (j = 0; j < MAXSID; ++j) {
206 if (hssids[j] != -1) {
207 for (i = 0; i < 32; i++) {
208 write_sid(i, 0, hssids[j]);
209 }
210 }
211 }
212
213 log_message(LOG_DEFAULT, "PCI HardSID: opened at $%X with %d SIDs.", HSDevBAR->BaseAddress, sids_found);
214
215 return 0;
216 }
217
hs_os4_close(void)218 int hs_os4_close(void)
219 {
220 unsigned int i, j;
221
222 /* mute all sids */
223 for (j = 0; j < MAXSID; ++j) {
224 if (hssids[j] != -1) {
225 for (i = 0; i < 32; i++) {
226 write_sid(i, 0, hssids[j]);
227 }
228 }
229 hssids[j] = -1;
230 }
231
232 close_device();
233
234 log_message(LOG_DEFAULT, "PCI HardSID: closed.");
235
236 sids_found = -1;
237
238 return 0;
239 }
240
read_sid(unsigned char reg,int chipno)241 static unsigned char read_sid(unsigned char reg, int chipno)
242 {
243 unsigned char ret;
244
245 HSDevPCI->OutByte(HSDevBAR->BaseAddress + 4, ((chipno << 6) | (reg & 0x1f) | 0x20));
246 usleep(2);
247 HSDevPCI->OutByte(HSDevBAR->BaseAddress, 0x20);
248 ret = HSDevPCI->InByte(HSDevBAR->BaseAddress);
249 HSDevPCI->OutByte(HSDevBAR->BaseAddress, 0x80);
250
251 return ret;
252 }
253
write_sid(unsigned char reg,unsigned char data,int chipno)254 static void write_sid(unsigned char reg, unsigned char data, int chipno)
255 {
256 HSDevPCI->OutWord(HSDevBAR->BaseAddress + 3, ((chipno << 14) | (reg & 0x1f) << 8) | data);
257 }
258
hs_os4_available(void)259 int hs_os4_available(void)
260 {
261 return sids_found;
262 }
263 #endif
264 #endif
265