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)
50 pci = (PCIAccess *)a->backend_data;
54 IExec->DropInterface((struct Interface *)pci->ipci);
57 IExec->CloseLibrary((struct Library *)pci->expansion);
58 pci->expansion = NULL;
61 a->backend_data = NULL;
66 aos_open_pci_interface(struct pci_access *a)
71 if (NULL == a->backend_data) {
72 pci = pci_malloc(a, sizeof(PCIAccess));
73 a->backend_data = pci;
74 pci->expansion = (struct ExpansionBase *)IExec->OpenLibrary("expansion.library", 0);
75 if(NULL == pci->expansion) {
76 a->warning("Unable to open expansion.library");
77 aos_close_pci_interface(a);
79 pci->ipci = (struct PCIIFace *)IExec->GetInterface((struct Library *)pci->expansion, "pci", 1, TAG_DONE);
80 if(NULL == pci->ipci) {
81 a->warning("Unable to obtain pci interface");
82 aos_close_pci_interface(a);
88 res = TRUE; // already opened
95 aos_expansion_detect(struct pci_access *a)
98 struct PCIDevice *device = NULL;
101 if(TRUE == aos_open_pci_interface(a)) {
102 pci = a->backend_data;
104 // Try to read PCI first device
105 device = pci->ipci->FindDeviceTags(FDT_Index, 0);
107 a->warning("AmigaOS Expansion PCI interface cannot find any device");
108 aos_close_pci_interface(a);
110 pci->ipci->FreeDevice(device);
119 aos_expansion_init(struct pci_access *a)
121 // to avoid flushing of version tag
122 static STRPTR USED ver = (STRPTR)VERSTAG;
124 if (!aos_open_pci_interface(a)) {
126 a->error("AmigaOS Expansion PCI interface cannot be accessed.");
131 aos_expansion_cleanup(struct pci_access *a)
133 aos_close_pci_interface(a);
137 aos_expansion_scan(struct pci_access *a)
139 struct PCIDevice *device = NULL;
140 PCIAccess *pci = NULL;
147 pci = a->backend_data;
149 // 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
150 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
152 d = pci_alloc_dev(a);
153 d->domain = 0; // only one domain for AmigaOS
154 device->GetAddress(&bus_num, &dev_num, &fn_num);
158 d->backend_data = device;
159 d->vendor_id = device->ReadConfigWord(PCI_VENDOR_ID);
160 d->device_id = device->ReadConfigWord(PCI_DEVICE_ID);
161 d->known_fields = PCI_FILL_IDENT;
162 d->hdrtype = device->ReadConfigByte(PCI_HEADER_TYPE) & ~PCI_HEADER_TYPE_MULTIFUNCTION;
164 a->debug(" Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id);
167 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
172 aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len)
176 if (d->backend_data) {
177 for (int i = 0; i < len; i++) {
178 // byte by byte to avoid endianness troubles
179 *ptr = ((struct PCIDevice *)(d->backend_data))->ReadConfigByte(pos + i);
189 aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len)
194 if (d->backend_data) {
195 for (int i = 0; i < len; i++) {
196 // byte by byte to avoid endianness troubles
197 ((struct PCIDevice *)(d->backend_data))->WriteConfigByte(pos + i, *ptr);
207 aos_expansion_init_dev(struct pci_dev *d)
209 d->backend_data = NULL; // struct PCIDevice * to be obtained
213 aos_expansion_cleanup_dev(struct pci_dev *d)
217 if (d->backend_data && d->access->backend_data) {
218 pci = d->access->backend_data;
219 pci->ipci->FreeDevice((struct PCIDevice *)d->backend_data);
220 d->backend_data = NULL;
224 struct pci_methods pm_aos_expansion = {
226 "The Expansion.library on AmigaOS 4.x",
227 NULL, // config, called after allocation of pci_access, if assigned
228 aos_expansion_detect, // detect, mandatory because called without check
229 aos_expansion_init, // init, called once access chosen, eventually after detect
230 aos_expansion_cleanup, // cleanup, called at the end
232 pci_generic_fill_info,
236 aos_expansion_init_dev,
237 aos_expansion_cleanup_dev,