]> mj.ucw.cz Git - pciutils.git/blob - lib/aos-expansion.c
New back-end for AmigaOS on PowerPC
[pciutils.git] / lib / aos-expansion.c
1 /*
2  *      The PCI Library -- Configuration Access via AmigaOS 4.x expansion.library
3  *
4  *      Copyright (c) 2024 Olrick Lefebvre <olrick.lefebvre@olrick.fr>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #define _GNU_SOURCE
12
13 #include <proto/exec.h>
14 #include <exec/types.h>
15 #include <proto/expansion.h>
16 #include <interfaces/expansion.h>
17
18
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>
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <sys/unistd.h>
30
31 #include "internal.h"
32
33
34 // custom Amiga x.y version tag
35 #define VERSTAG "\0$VER: lspci 3.10 (02.01.2024) AmigaOS4 port"
36
37
38 /*** AmigaOS access support ***/
39
40 typedef struct _PCIAccess {
41         struct ExpansionBase *expansion;
42         struct PCIIFace *ipci;
43 } PCIAccess;
44
45 static void 
46 aos_close_pci_interface(struct pci_access *a)
47 {
48         PCIAccess *pci;
49
50         pci = (PCIAccess *)a->backend_data;
51         if (pci) {
52                 if (pci->expansion) {
53                         if (pci->ipci) {
54                                 IExec->DropInterface((struct Interface *)pci->ipci);
55                                 pci->ipci = NULL;
56                         }
57                         IExec->CloseLibrary((struct Library *)pci->expansion);
58                         pci->expansion = NULL;
59                 }
60                 pci_mfree(pci);
61                 a->backend_data = NULL;
62         }
63 }
64
65 static BOOL 
66 aos_open_pci_interface(struct pci_access *a)
67 {
68         PCIAccess *pci;
69         BOOL res = FALSE;
70
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);
78                 } else {
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);                     
83                         } else {
84                                 res = TRUE;
85                         }
86                 }
87         } else {
88                 res = TRUE;  // already opened
89         }
90
91         return res;
92 }
93
94 static int 
95 aos_expansion_detect(struct pci_access *a)
96 {
97         int res = FALSE;
98         struct PCIDevice *device = NULL;
99         PCIAccess *pci;
100
101         if(TRUE == aos_open_pci_interface(a)) { 
102                 pci = a->backend_data;
103
104                 // Try to read PCI first device
105                 device = pci->ipci->FindDeviceTags(FDT_Index, 0);
106                 if(NULL == device) {
107                         a->warning("AmigaOS Expansion PCI interface cannot find any device");
108                         aos_close_pci_interface(a);
109                 } else {
110                         pci->ipci->FreeDevice(device);
111                         res = TRUE;
112                 }
113         }
114         
115         return res;
116 }
117
118 static void 
119 aos_expansion_init(struct pci_access *a)
120 {
121         // to avoid flushing of version tag
122         static STRPTR USED ver = (STRPTR)VERSTAG;
123
124         if (!aos_open_pci_interface(a)) {
125                 a->debug("\n");
126                 a->error("AmigaOS Expansion PCI interface cannot be accessed.");
127         }
128 }
129
130 static void 
131 aos_expansion_cleanup(struct pci_access *a)
132 {
133         aos_close_pci_interface(a);
134 }
135
136 static void 
137 aos_expansion_scan(struct pci_access *a)
138 {
139         struct PCIDevice *device = NULL;
140         PCIAccess *pci = NULL;
141         UBYTE bus_num;
142         UBYTE dev_num;
143         UBYTE fn_num;
144         struct pci_dev *d;
145         int found_devs = 0;
146
147         pci = a->backend_data;
148
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);
151         while (device) {
152                 d = pci_alloc_dev(a);
153                 d->domain = 0; // only one domain for AmigaOS
154                 device->GetAddress(&bus_num, &dev_num, &fn_num);
155                 d->bus = bus_num;
156                 d->dev = dev_num;
157                 d->func = 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;
163                 pci_link_dev(a, d);
164                 a->debug("  Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id);
165
166                 found_devs++;
167                 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
168         }
169 }
170
171 static int 
172 aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len)
173 {
174         int res = FALSE;
175         byte *ptr = buf;
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);
180                         ptr++;
181                         res = TRUE;
182                 }
183         }
184
185         return res;
186 }
187
188 static int 
189 aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len)
190 {
191         int res = FALSE;
192         byte *ptr = buf;
193
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);
198                         ptr++;
199                         res = TRUE;
200                 }
201         }
202
203         return res;
204 }
205
206 static void 
207 aos_expansion_init_dev(struct pci_dev *d)
208 {
209         d->backend_data = NULL; // struct PCIDevice * to be obtained
210 }
211
212 static void 
213 aos_expansion_cleanup_dev(struct pci_dev *d)
214 {
215         PCIAccess *pci;
216
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;
221         }
222 }
223
224 struct pci_methods pm_aos_expansion = {
225         "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
231         aos_expansion_scan,
232         pci_generic_fill_info,
233         aos_expansion_read,
234         aos_expansion_write,
235         NULL,                   // read_vpd
236         aos_expansion_init_dev,
237         aos_expansion_cleanup_dev,
238 };