]> mj.ucw.cz Git - pciutils.git/blob - lib/aos-expansion.c
libpci: hwdb: Remove ID_SUBSYSTEM and ID_GEN_SUBSYSTEM usage from pci_id_hwdb_lookup()
[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: pciutils " PCILIB_VERSION " (" PCILIB_DATE_AMIGAOS ") 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 = a->backend_data;
49
50         if (pci) {
51                 if (pci->expansion) {
52                         if (pci->ipci) {
53                                 IExec->DropInterface((struct Interface *)pci->ipci);
54                                 pci->ipci = NULL;
55                         }
56                         IExec->CloseLibrary((struct Library *)pci->expansion);
57                         pci->expansion = NULL;
58                 }
59                 pci_mfree(pci);
60                 a->backend_data = NULL;
61         }
62 }
63
64 static BOOL 
65 aos_open_pci_interface(struct pci_access *a)
66 {
67         PCIAccess *pci;
68         BOOL res = FALSE;
69
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);
77                 } else {
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);                     
82                         } else {
83                                 res = TRUE;
84                         }
85                 }
86         } else {
87                 res = TRUE;  // already opened
88         }
89
90         return res;
91 }
92
93 static int 
94 aos_expansion_detect(struct pci_access *a)
95 {
96         int res = FALSE;
97         struct PCIDevice *device = NULL;
98         PCIAccess *pci;
99
100         if(TRUE == aos_open_pci_interface(a)) { 
101                 pci = a->backend_data;
102
103                 // Try to read PCI first device
104                 device = pci->ipci->FindDeviceTags(FDT_Index, 0);
105                 if(NULL == device) {
106                         a->warning("AmigaOS Expansion PCI interface cannot find any device");
107                         aos_close_pci_interface(a);
108                 } else {
109                         pci->ipci->FreeDevice(device);
110                         res = TRUE;
111                 }
112         }
113         
114         return res;
115 }
116
117 static void 
118 aos_expansion_init(struct pci_access *a)
119 {
120         // to avoid flushing of version tag
121         static STRPTR USED ver = (STRPTR)VERSTAG;
122
123         if (!aos_open_pci_interface(a)) {
124                 a->debug("\n");
125                 a->error("AmigaOS Expansion PCI interface cannot be accessed.");
126         }
127 }
128
129 static void 
130 aos_expansion_cleanup(struct pci_access *a)
131 {
132         aos_close_pci_interface(a);
133 }
134
135 static void 
136 aos_expansion_scan(struct pci_access *a)
137 {
138         struct PCIDevice *device = NULL;
139         PCIAccess *pci = NULL;
140         UBYTE bus_num;
141         UBYTE dev_num;
142         UBYTE fn_num;
143         struct pci_dev *d;
144         int found_devs = 0;
145
146         pci = a->backend_data;
147
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);
150         while (device) {
151                 d = pci_alloc_dev(a);
152                 d->domain = 0; // only one domain for AmigaOS
153                 device->GetAddress(&bus_num, &dev_num, &fn_num);
154                 d->bus = bus_num;
155                 d->dev = dev_num;
156                 d->func = 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;
162                 pci_link_dev(a, d);
163                 a->debug("  Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id);
164
165                 found_devs++;
166                 device = pci->ipci->FindDeviceTags(FDT_Index, found_devs);
167         }
168 }
169
170 static int 
171 aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len)
172 {
173         int res = FALSE;
174         byte *ptr = buf;
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);
179                         ptr++;
180                         res = TRUE;
181                 }
182         }
183
184         return res;
185 }
186
187 static int 
188 aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len)
189 {
190         int res = FALSE;
191         byte *ptr = buf;
192
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);
197                         ptr++;
198                         res = TRUE;
199                 }
200         }
201
202         return res;
203 }
204
205 static void 
206 aos_expansion_init_dev(struct pci_dev *d)
207 {
208         d->backend_data = NULL; // struct PCIDevice * to be obtained
209 }
210
211 static void 
212 aos_expansion_cleanup_dev(struct pci_dev *d)
213 {
214         PCIAccess *pci;
215
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;
220         }
221 }
222
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,
235 };