xref: /aosp_15_r20/external/pciutils/lib/aos-expansion.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *	The PCI Library -- Configuration Access via AmigaOS 4.x expansion.library
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 2024 Olrick Lefebvre <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *	SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker #define _GNU_SOURCE
12*c2e0c6b5SAndroid Build Coastguard Worker 
13*c2e0c6b5SAndroid Build Coastguard Worker #include <proto/exec.h>
14*c2e0c6b5SAndroid Build Coastguard Worker #include <exec/types.h>
15*c2e0c6b5SAndroid Build Coastguard Worker #include <proto/expansion.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <interfaces/expansion.h>
17*c2e0c6b5SAndroid Build Coastguard Worker 
18*c2e0c6b5SAndroid Build Coastguard Worker 
19*c2e0c6b5SAndroid Build Coastguard Worker // have to undef PCI values to avoid redefine warning
20*c2e0c6b5SAndroid Build Coastguard Worker #undef PCI_BASE_ADDRESS_MEM_MASK
21*c2e0c6b5SAndroid Build Coastguard Worker #undef PCI_BASE_ADDRESS_IO_MASK
22*c2e0c6b5SAndroid Build Coastguard Worker #undef PCI_ROM_ADDRESS_MASK
23*c2e0c6b5SAndroid Build Coastguard Worker #include <expansion/pci.h>
24*c2e0c6b5SAndroid Build Coastguard Worker 
25*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
26*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
27*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
28*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
29*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/unistd.h>
30*c2e0c6b5SAndroid Build Coastguard Worker 
31*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
32*c2e0c6b5SAndroid Build Coastguard Worker 
33*c2e0c6b5SAndroid Build Coastguard Worker 
34*c2e0c6b5SAndroid Build Coastguard Worker // custom Amiga x.y version tag
35*c2e0c6b5SAndroid Build Coastguard Worker #define VERSTAG "\0$VER: pciutils " PCILIB_VERSION " (" PCILIB_DATE_AMIGAOS ") AmigaOS4 port"
36*c2e0c6b5SAndroid Build Coastguard Worker 
37*c2e0c6b5SAndroid Build Coastguard Worker 
38*c2e0c6b5SAndroid Build Coastguard Worker /*** AmigaOS access support ***/
39*c2e0c6b5SAndroid Build Coastguard Worker 
40*c2e0c6b5SAndroid Build Coastguard Worker typedef struct _PCIAccess {
41*c2e0c6b5SAndroid Build Coastguard Worker 	struct ExpansionBase *expansion;
42*c2e0c6b5SAndroid Build Coastguard Worker 	struct PCIIFace *ipci;
43*c2e0c6b5SAndroid Build Coastguard Worker } PCIAccess;
44*c2e0c6b5SAndroid Build Coastguard Worker 
45*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_close_pci_interface(struct pci_access * a)46*c2e0c6b5SAndroid Build Coastguard Worker aos_close_pci_interface(struct pci_access *a)
47*c2e0c6b5SAndroid Build Coastguard Worker {
48*c2e0c6b5SAndroid Build Coastguard Worker 	PCIAccess *pci = a->backend_data;
49*c2e0c6b5SAndroid Build Coastguard Worker 
50*c2e0c6b5SAndroid Build Coastguard Worker 	if (pci) {
51*c2e0c6b5SAndroid Build Coastguard Worker 		if (pci->expansion) {
52*c2e0c6b5SAndroid Build Coastguard Worker 			if (pci->ipci) {
53*c2e0c6b5SAndroid Build Coastguard Worker 				IExec->DropInterface((struct Interface *)pci->ipci);
54*c2e0c6b5SAndroid Build Coastguard Worker 				pci->ipci = NULL;
55*c2e0c6b5SAndroid Build Coastguard Worker 			}
56*c2e0c6b5SAndroid Build Coastguard Worker 			IExec->CloseLibrary((struct Library *)pci->expansion);
57*c2e0c6b5SAndroid Build Coastguard Worker 			pci->expansion = NULL;
58*c2e0c6b5SAndroid Build Coastguard Worker 		}
59*c2e0c6b5SAndroid Build Coastguard Worker 		pci_mfree(pci);
60*c2e0c6b5SAndroid Build Coastguard Worker 		a->backend_data = NULL;
61*c2e0c6b5SAndroid Build Coastguard Worker 	}
62*c2e0c6b5SAndroid Build Coastguard Worker }
63*c2e0c6b5SAndroid Build Coastguard Worker 
64*c2e0c6b5SAndroid Build Coastguard Worker static BOOL
aos_open_pci_interface(struct pci_access * a)65*c2e0c6b5SAndroid Build Coastguard Worker aos_open_pci_interface(struct pci_access *a)
66*c2e0c6b5SAndroid Build Coastguard Worker {
67*c2e0c6b5SAndroid Build Coastguard Worker 	PCIAccess *pci;
68*c2e0c6b5SAndroid Build Coastguard Worker 	BOOL res = FALSE;
69*c2e0c6b5SAndroid Build Coastguard Worker 
70*c2e0c6b5SAndroid Build Coastguard Worker 	if (NULL == a->backend_data) {
71*c2e0c6b5SAndroid Build Coastguard Worker 		pci = pci_malloc(a, sizeof(PCIAccess));
72*c2e0c6b5SAndroid Build Coastguard Worker 		a->backend_data = pci;
73*c2e0c6b5SAndroid Build Coastguard Worker 		pci->expansion = (struct ExpansionBase *)IExec->OpenLibrary("expansion.library", 0);
74*c2e0c6b5SAndroid Build Coastguard Worker 		if(NULL == pci->expansion) {
75*c2e0c6b5SAndroid Build Coastguard Worker 			a->warning("Unable to open expansion.library");
76*c2e0c6b5SAndroid Build Coastguard Worker 			aos_close_pci_interface(a);
77*c2e0c6b5SAndroid Build Coastguard Worker 		} else {
78*c2e0c6b5SAndroid Build Coastguard Worker 			pci->ipci = (struct PCIIFace *)IExec->GetInterface((struct Library *)pci->expansion, "pci", 1, TAG_DONE);
79*c2e0c6b5SAndroid Build Coastguard Worker 			if(NULL == pci->ipci) {
80*c2e0c6b5SAndroid Build Coastguard Worker 				a->warning("Unable to obtain pci interface");
81*c2e0c6b5SAndroid Build Coastguard Worker 				aos_close_pci_interface(a);
82*c2e0c6b5SAndroid Build Coastguard Worker 			} else {
83*c2e0c6b5SAndroid Build Coastguard Worker 				res = TRUE;
84*c2e0c6b5SAndroid Build Coastguard Worker 			}
85*c2e0c6b5SAndroid Build Coastguard Worker 		}
86*c2e0c6b5SAndroid Build Coastguard Worker 	} else {
87*c2e0c6b5SAndroid Build Coastguard Worker 		res = TRUE;  // already opened
88*c2e0c6b5SAndroid Build Coastguard Worker 	}
89*c2e0c6b5SAndroid Build Coastguard Worker 
90*c2e0c6b5SAndroid Build Coastguard Worker 	return res;
91*c2e0c6b5SAndroid Build Coastguard Worker }
92*c2e0c6b5SAndroid Build Coastguard Worker 
93*c2e0c6b5SAndroid Build Coastguard Worker static int
aos_expansion_detect(struct pci_access * a)94*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_detect(struct pci_access *a)
95*c2e0c6b5SAndroid Build Coastguard Worker {
96*c2e0c6b5SAndroid Build Coastguard Worker 	int res = FALSE;
97*c2e0c6b5SAndroid Build Coastguard Worker 	struct PCIDevice *device = NULL;
98*c2e0c6b5SAndroid Build Coastguard Worker 	PCIAccess *pci;
99*c2e0c6b5SAndroid Build Coastguard Worker 
100*c2e0c6b5SAndroid Build Coastguard Worker 	if(TRUE == aos_open_pci_interface(a)) {
101*c2e0c6b5SAndroid Build Coastguard Worker 		pci = a->backend_data;
102*c2e0c6b5SAndroid Build Coastguard Worker 
103*c2e0c6b5SAndroid Build Coastguard Worker 		// Try to read PCI first device
104*c2e0c6b5SAndroid Build Coastguard Worker 		device = pci->ipci->FindDeviceTags(FDT_Index, 0);
105*c2e0c6b5SAndroid Build Coastguard Worker 		if(NULL == device) {
106*c2e0c6b5SAndroid Build Coastguard Worker 			a->warning("AmigaOS Expansion PCI interface cannot find any device");
107*c2e0c6b5SAndroid Build Coastguard Worker 			aos_close_pci_interface(a);
108*c2e0c6b5SAndroid Build Coastguard Worker 		} else {
109*c2e0c6b5SAndroid Build Coastguard Worker 			pci->ipci->FreeDevice(device);
110*c2e0c6b5SAndroid Build Coastguard Worker 			res = TRUE;
111*c2e0c6b5SAndroid Build Coastguard Worker 		}
112*c2e0c6b5SAndroid Build Coastguard Worker 	}
113*c2e0c6b5SAndroid Build Coastguard Worker 
114*c2e0c6b5SAndroid Build Coastguard Worker 	return res;
115*c2e0c6b5SAndroid Build Coastguard Worker }
116*c2e0c6b5SAndroid Build Coastguard Worker 
117*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_expansion_init(struct pci_access * a)118*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_init(struct pci_access *a)
119*c2e0c6b5SAndroid Build Coastguard Worker {
120*c2e0c6b5SAndroid Build Coastguard Worker 	// to avoid flushing of version tag
121*c2e0c6b5SAndroid Build Coastguard Worker 	static STRPTR USED ver = (STRPTR)VERSTAG;
122*c2e0c6b5SAndroid Build Coastguard Worker 
123*c2e0c6b5SAndroid Build Coastguard Worker 	if (!aos_open_pci_interface(a)) {
124*c2e0c6b5SAndroid Build Coastguard Worker 		a->debug("\n");
125*c2e0c6b5SAndroid Build Coastguard Worker 		a->error("AmigaOS Expansion PCI interface cannot be accessed.");
126*c2e0c6b5SAndroid Build Coastguard Worker 	}
127*c2e0c6b5SAndroid Build Coastguard Worker }
128*c2e0c6b5SAndroid Build Coastguard Worker 
129*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_expansion_cleanup(struct pci_access * a)130*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_cleanup(struct pci_access *a)
131*c2e0c6b5SAndroid Build Coastguard Worker {
132*c2e0c6b5SAndroid Build Coastguard Worker 	aos_close_pci_interface(a);
133*c2e0c6b5SAndroid Build Coastguard Worker }
134*c2e0c6b5SAndroid Build Coastguard Worker 
135*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_expansion_scan(struct pci_access * a)136*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_scan(struct pci_access *a)
137*c2e0c6b5SAndroid Build Coastguard Worker {
138*c2e0c6b5SAndroid Build Coastguard Worker 	struct PCIDevice *device = NULL;
139*c2e0c6b5SAndroid Build Coastguard Worker 	PCIAccess *pci = NULL;
140*c2e0c6b5SAndroid Build Coastguard Worker 	UBYTE bus_num;
141*c2e0c6b5SAndroid Build Coastguard Worker 	UBYTE dev_num;
142*c2e0c6b5SAndroid Build Coastguard Worker 	UBYTE fn_num;
143*c2e0c6b5SAndroid Build Coastguard Worker 	struct pci_dev *d;
144*c2e0c6b5SAndroid Build Coastguard Worker 	int found_devs = 0;
145*c2e0c6b5SAndroid Build Coastguard Worker 
146*c2e0c6b5SAndroid Build Coastguard Worker 	pci = a->backend_data;
147*c2e0c6b5SAndroid Build Coastguard Worker 
148*c2e0c6b5SAndroid Build Coastguard Worker 	// X1000 has a bug which left shifts secondary bus by one bit, so we don't scan but get all devices identified by the system
149*c2e0c6b5SAndroid Build Coastguard Worker 	device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
150*c2e0c6b5SAndroid Build Coastguard Worker 	while (device) {
151*c2e0c6b5SAndroid Build Coastguard Worker 		d = pci_alloc_dev(a);
152*c2e0c6b5SAndroid Build Coastguard Worker 		d->domain = 0; // only one domain for AmigaOS
153*c2e0c6b5SAndroid Build Coastguard Worker 		device->GetAddress(&bus_num, &dev_num, &fn_num);
154*c2e0c6b5SAndroid Build Coastguard Worker 		d->bus = bus_num;
155*c2e0c6b5SAndroid Build Coastguard Worker 		d->dev = dev_num;
156*c2e0c6b5SAndroid Build Coastguard Worker 		d->func = fn_num;
157*c2e0c6b5SAndroid Build Coastguard Worker 		d->backend_data = device;
158*c2e0c6b5SAndroid Build Coastguard Worker 		d->vendor_id = device->ReadConfigWord(PCI_VENDOR_ID);
159*c2e0c6b5SAndroid Build Coastguard Worker 		d->device_id = device->ReadConfigWord(PCI_DEVICE_ID);
160*c2e0c6b5SAndroid Build Coastguard Worker 		d->known_fields = PCI_FILL_IDENT;
161*c2e0c6b5SAndroid Build Coastguard Worker 		d->hdrtype = device->ReadConfigByte(PCI_HEADER_TYPE) & ~PCI_HEADER_TYPE_MULTIFUNCTION;
162*c2e0c6b5SAndroid Build Coastguard Worker 		pci_link_dev(a, d);
163*c2e0c6b5SAndroid Build Coastguard Worker 		a->debug("  Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id);
164*c2e0c6b5SAndroid Build Coastguard Worker 
165*c2e0c6b5SAndroid Build Coastguard Worker 		found_devs++;
166*c2e0c6b5SAndroid Build Coastguard Worker 		device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
167*c2e0c6b5SAndroid Build Coastguard Worker 	}
168*c2e0c6b5SAndroid Build Coastguard Worker }
169*c2e0c6b5SAndroid Build Coastguard Worker 
170*c2e0c6b5SAndroid Build Coastguard Worker static int
aos_expansion_read(struct pci_dev * d,int pos,byte * buf,int len)171*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len)
172*c2e0c6b5SAndroid Build Coastguard Worker {
173*c2e0c6b5SAndroid Build Coastguard Worker 	int res = FALSE;
174*c2e0c6b5SAndroid Build Coastguard Worker 	byte *ptr = buf;
175*c2e0c6b5SAndroid Build Coastguard Worker 	if (d->backend_data) {
176*c2e0c6b5SAndroid Build Coastguard Worker 		for (int i = 0; i < len; i++) {
177*c2e0c6b5SAndroid Build Coastguard Worker 			// byte by byte to avoid endianness troubles
178*c2e0c6b5SAndroid Build Coastguard Worker 			*ptr = ((struct PCIDevice *)(d->backend_data))->ReadConfigByte(pos + i);
179*c2e0c6b5SAndroid Build Coastguard Worker 			ptr++;
180*c2e0c6b5SAndroid Build Coastguard Worker 			res = TRUE;
181*c2e0c6b5SAndroid Build Coastguard Worker 		}
182*c2e0c6b5SAndroid Build Coastguard Worker 	}
183*c2e0c6b5SAndroid Build Coastguard Worker 
184*c2e0c6b5SAndroid Build Coastguard Worker 	return res;
185*c2e0c6b5SAndroid Build Coastguard Worker }
186*c2e0c6b5SAndroid Build Coastguard Worker 
187*c2e0c6b5SAndroid Build Coastguard Worker static int
aos_expansion_write(struct pci_dev * d,int pos,byte * buf,int len)188*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len)
189*c2e0c6b5SAndroid Build Coastguard Worker {
190*c2e0c6b5SAndroid Build Coastguard Worker 	int res = FALSE;
191*c2e0c6b5SAndroid Build Coastguard Worker 	byte *ptr = buf;
192*c2e0c6b5SAndroid Build Coastguard Worker 
193*c2e0c6b5SAndroid Build Coastguard Worker 	if (d->backend_data) {
194*c2e0c6b5SAndroid Build Coastguard Worker 		for (int i = 0; i < len; i++) {
195*c2e0c6b5SAndroid Build Coastguard Worker 			// byte by byte to avoid endianness troubles
196*c2e0c6b5SAndroid Build Coastguard Worker 			((struct PCIDevice *)(d->backend_data))->WriteConfigByte(pos + i, *ptr);
197*c2e0c6b5SAndroid Build Coastguard Worker 			ptr++;
198*c2e0c6b5SAndroid Build Coastguard Worker 			res = TRUE;
199*c2e0c6b5SAndroid Build Coastguard Worker 		}
200*c2e0c6b5SAndroid Build Coastguard Worker 	}
201*c2e0c6b5SAndroid Build Coastguard Worker 
202*c2e0c6b5SAndroid Build Coastguard Worker 	return res;
203*c2e0c6b5SAndroid Build Coastguard Worker }
204*c2e0c6b5SAndroid Build Coastguard Worker 
205*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_expansion_init_dev(struct pci_dev * d)206*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_init_dev(struct pci_dev *d)
207*c2e0c6b5SAndroid Build Coastguard Worker {
208*c2e0c6b5SAndroid Build Coastguard Worker 	d->backend_data = NULL; // struct PCIDevice * to be obtained
209*c2e0c6b5SAndroid Build Coastguard Worker }
210*c2e0c6b5SAndroid Build Coastguard Worker 
211*c2e0c6b5SAndroid Build Coastguard Worker static void
aos_expansion_cleanup_dev(struct pci_dev * d)212*c2e0c6b5SAndroid Build Coastguard Worker aos_expansion_cleanup_dev(struct pci_dev *d)
213*c2e0c6b5SAndroid Build Coastguard Worker {
214*c2e0c6b5SAndroid Build Coastguard Worker 	PCIAccess *pci;
215*c2e0c6b5SAndroid Build Coastguard Worker 
216*c2e0c6b5SAndroid Build Coastguard Worker 	if (d->backend_data && d->access->backend_data) {
217*c2e0c6b5SAndroid Build Coastguard Worker 		pci = d->access->backend_data;
218*c2e0c6b5SAndroid Build Coastguard Worker 		pci->ipci->FreeDevice((struct PCIDevice *)d->backend_data);
219*c2e0c6b5SAndroid Build Coastguard Worker 		d->backend_data = NULL;
220*c2e0c6b5SAndroid Build Coastguard Worker 	}
221*c2e0c6b5SAndroid Build Coastguard Worker }
222*c2e0c6b5SAndroid Build Coastguard Worker 
223*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_aos_expansion = {
224*c2e0c6b5SAndroid Build Coastguard Worker 	.name = "aos-expansion",
225*c2e0c6b5SAndroid Build Coastguard Worker 	.help = "The Expansion.library on AmigaOS 4.x",
226*c2e0c6b5SAndroid Build Coastguard Worker 	.detect = aos_expansion_detect,		// detect, mandatory because called without check
227*c2e0c6b5SAndroid Build Coastguard Worker 	.init = aos_expansion_init,		// init, called once access chosen, eventually after detect
228*c2e0c6b5SAndroid Build Coastguard Worker 	.cleanup = aos_expansion_cleanup,	// cleanup, called at the end
229*c2e0c6b5SAndroid Build Coastguard Worker 	.scan = aos_expansion_scan,
230*c2e0c6b5SAndroid Build Coastguard Worker 	.fill_info = pci_generic_fill_info,
231*c2e0c6b5SAndroid Build Coastguard Worker 	.read = aos_expansion_read,
232*c2e0c6b5SAndroid Build Coastguard Worker 	.write = aos_expansion_write,
233*c2e0c6b5SAndroid Build Coastguard Worker 	.init_dev = aos_expansion_init_dev,
234*c2e0c6b5SAndroid Build Coastguard Worker 	.cleanup_dev = aos_expansion_cleanup_dev,
235*c2e0c6b5SAndroid Build Coastguard Worker };
236