2 * The PCI Library -- Configuration Access via AmigaOS 4.x expansion.library
4 * Copyright (c) 2024 Olrick Lefebvre <olrick.lefebvre@olrick.fr>
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <proto/exec.h>
14 #include <exec/types.h>
15 #include <proto/expansion.h>
16 #include <interfaces/expansion.h>
19 // have to undef PCI values to avoid redefine warning
20 #undef PCI_BASE_ADDRESS_MEM_MASK
21 #undef PCI_BASE_ADDRESS_IO_MASK
22 #undef PCI_ROM_ADDRESS_MASK
23 #include <expansion/pci.h>
29 #include <sys/unistd.h>
34 // custom Amiga x.y version tag
35 #define VERSTAG "\0$VER: pciutils " PCILIB_VERSION " (" PCILIB_DATE_AMIGAOS ") AmigaOS4 port"
38 /*** AmigaOS access support ***/
40 typedef struct _PCIAccess {
41 struct ExpansionBase *expansion;
42 struct PCIIFace *ipci;
46 aos_close_pci_interface(struct pci_access *a)
48 PCIAccess *pci = a->backend_data;
53 IExec->DropInterface((struct Interface *)pci->ipci);
56 IExec->CloseLibrary((struct Library *)pci->expansion);
57 pci->expansion = NULL;
60 a->backend_data = NULL;
65 aos_open_pci_interface(struct pci_access *a)
70 if (NULL == a->backend_data) {
71 pci = pci_malloc(a, sizeof(PCIAccess));
72 a->backend_data = pci;
73 pci->expansion = (struct ExpansionBase *)IExec->OpenLibrary("expansion.library", 0);
74 if(NULL == pci->expansion) {
75 a->warning("Unable to open expansion.library");
76 aos_close_pci_interface(a);
78 pci->ipci = (struct PCIIFace *)IExec->GetInterface((struct Library *)pci->expansion, "pci", 1, TAG_DONE);
79 if(NULL == pci->ipci) {
80 a->warning("Unable to obtain pci interface");
81 aos_close_pci_interface(a);
87 res = TRUE; // already opened
94 aos_expansion_detect(struct pci_access *a)
97 struct PCIDevice *device = NULL;
100 if(TRUE == aos_open_pci_interface(a)) {
101 pci = a->backend_data;
103 // Try to read PCI first device
104 device = pci->ipci->FindDeviceTags(FDT_Index, 0);
106 a->warning("AmigaOS Expansion PCI interface cannot find any device");
107 aos_close_pci_interface(a);
109 pci->ipci->FreeDevice(device);
118 aos_expansion_init(struct pci_access *a)
120 // to avoid flushing of version tag
121 static STRPTR USED ver = (STRPTR)VERSTAG;
123 if (!aos_open_pci_interface(a)) {
125 a->error("AmigaOS Expansion PCI interface cannot be accessed.");
130 aos_expansion_cleanup(struct pci_access *a)
132 aos_close_pci_interface(a);
136 aos_expansion_scan(struct pci_access *a)
138 struct PCIDevice *device = NULL;
139 PCIAccess *pci = NULL;
146 pci = a->backend_data;
148 // 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 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
151 d = pci_alloc_dev(a);
152 d->domain = 0; // only one domain for AmigaOS
153 device->GetAddress(&bus_num, &dev_num, &fn_num);
157 d->backend_data = device;
158 d->vendor_id = device->ReadConfigWord(PCI_VENDOR_ID);
159 d->device_id = device->ReadConfigWord(PCI_DEVICE_ID);
160 d->known_fields = PCI_FILL_IDENT;
161 d->hdrtype = device->ReadConfigByte(PCI_HEADER_TYPE) & ~PCI_HEADER_TYPE_MULTIFUNCTION;
163 a->debug(" Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id);
166 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
171 aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len)
175 if (d->backend_data) {
176 for (int i = 0; i < len; i++) {
177 // byte by byte to avoid endianness troubles
178 *ptr = ((struct PCIDevice *)(d->backend_data))->ReadConfigByte(pos + i);
188 aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len)
193 if (d->backend_data) {
194 for (int i = 0; i < len; i++) {
195 // byte by byte to avoid endianness troubles
196 ((struct PCIDevice *)(d->backend_data))->WriteConfigByte(pos + i, *ptr);
206 aos_expansion_init_dev(struct pci_dev *d)
208 d->backend_data = NULL; // struct PCIDevice * to be obtained
212 aos_expansion_cleanup_dev(struct pci_dev *d)
216 if (d->backend_data && d->access->backend_data) {
217 pci = d->access->backend_data;
218 pci->ipci->FreeDevice((struct PCIDevice *)d->backend_data);
219 d->backend_data = NULL;
223 struct pci_methods pm_aos_expansion = {
224 .name = "aos-expansion",
225 .help = "The Expansion.library on AmigaOS 4.x",
226 .detect = aos_expansion_detect, // detect, mandatory because called without check
227 .init = aos_expansion_init, // init, called once access chosen, eventually after detect
228 .cleanup = aos_expansion_cleanup, // cleanup, called at the end
229 .scan = aos_expansion_scan,
230 .fill_info = pci_generic_fill_info,
231 .read = aos_expansion_read,
232 .write = aos_expansion_write,
233 .init_dev = aos_expansion_init_dev,
234 .cleanup_dev = aos_expansion_cleanup_dev,