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