From: Martin Mares Date: Mon, 8 Jan 2024 22:29:44 +0000 (+0100) Subject: New back-end for AmigaOS on PowerPC X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=d4423fe4fb11c3efeb557236bb5db15e2d732b4b;p=pciutils.git New back-end for AmigaOS on PowerPC Contributed by Olrick Lefebvre --- diff --git a/README b/README index 04e9348..955bd7f 100644 --- a/README +++ b/README @@ -32,6 +32,7 @@ In runs on the following systems: Darwin (via IOKit) DOS/DJGPP (via i386 ports) SylixOS (via /proc/pci) + AmigaOS on PPC (via Expansion library) It should be very easy to add support for other systems as well (volunteers wanted; if you want to try that, I'll be very glad to see the patches and diff --git a/lib/Makefile b/lib/Makefile index a89ac14..bacdbc5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -75,6 +75,10 @@ ifdef PCI_HAVE_PM_WIN32_SYSDBG OBJS += win32-sysdbg endif +ifdef PCI_HAVE_PM_AOS_EXPANSION +OBJS += aos-expansion +endif + all: $(PCILIB) $(PCILIBPC) ifeq ($(SHARED),no) diff --git a/lib/aos-expansion.c b/lib/aos-expansion.c new file mode 100644 index 0000000..6d80bd3 --- /dev/null +++ b/lib/aos-expansion.c @@ -0,0 +1,316 @@ +/* + * The PCI Library -- Configuration Access via AmigaOS 4.x expansion.library + * + * Copyright (c) 2024 Olrick Lefebvre + * + * Can be freely distributed and used under the terms of the GNU GPL v2+. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#define _GNU_SOURCE + +#if defined KDEBUG + #if defined __AMIGAOS4__ + #include + #endif +#endif +#include +#include +#include + + +// have to undef PCI values to avoid redefine warning +#undef PCI_BASE_ADDRESS_MEM_MASK +#undef PCI_BASE_ADDRESS_IO_MASK +#undef PCI_ROM_ADDRESS_MASK +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + + +// custom Amiga x.y version tag +#define VERSTAG "\0$VER: lspci 3.10 (02.01.2024) AmigaOS4 port" + + +// Debug macros +///////////////////////////////////////////////////////////////////////// + +#define __PRIV_log(lvl, fmt, ...) fprintf(stderr, "[" lvl "] (%s:%d: errno: %s) " fmt "\n", __FILE__, __LINE__, clean_errno(), __VA_ARGS__) + +#ifndef DEBUG + #define dbg_print(M, ...) +#else + #if defined KDEBUG && defined __AMIGAOS4__ + #define __PRIV_debug(fmt, ...) IExec->DebugPrintF("DEBUG %s:%d: "fmt"\n", __FILE__, __LINE__, __VA_ARGS__) + #undef __PRIV_log + #define __PRIV_log(lvl, fmt, ...) IExec->DebugPrintF("[" lvl "] (%s:%d: errno: %s) " fmt "\n", __FILE__, __LINE__, clean_errno(), __VA_ARGS__) + #else + #define __PRIV_debug(fmt, ...) fprintf(stderr, "DEBUG %s:%d: "fmt"\n", __FILE__, __LINE__, __VA_ARGS__) + #endif + #define dbg_print(...) __PRIV_debug(__VA_ARGS__, 0) +#endif + + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) + +#define log_err(...) __PRIV_log("ERROR", __VA_ARGS__, 0) +#define log_warn(...) __PRIV_log("WARN", __VA_ARGS__, 0) +#define log_info(...) __PRIV_log("INFO", __VA_ARGS__, 0) + +#define check(A, ...) if(!(A)) { log_err(__VA_ARGS__); errno=0; goto on_error; } +#define sentinel(...) { log_err(__VA_ARGS__); errno=0; goto on_error; } +#define check_mem(A) check((A), "Out of memory.") +#define check_debug(A, ...) if(!(A)) { debug(__VA_ARGS__); errno=0; goto on_error; } + + +// AmigaOS access support +///////////////////////////////////////////////////////////////////////// + +#define PCIACCESS_TAG 0xc0ffeeee +typedef struct _PCIAccess { + ULONG tag; // 0xc0ffeeee + struct ExpansionBase *expansion; + struct PCIIFace *ipci; +} PCIAccess; + + +static void aos_close_pci_interface(struct pci_access *a) +{ + PCIAccess *pci; + + if(NULL != a) + { + pci = (PCIAccess *)a->backend_data; + if(NULL != pci) + { + if(NULL != pci->expansion) + { + if(NULL != pci->ipci) + { + IExec->DropInterface((struct Interface *)pci->ipci); + pci->ipci = NULL; + } + IExec->CloseLibrary((struct Library *)pci->expansion); + pci->expansion = NULL; + } + pci_mfree(pci); + a->backend_data = NULL; + } + } +} + + +static BOOL aos_open_pci_interface(struct pci_access *a) +{ + PCIAccess *pci; + + check(NULL != a, "Null pci_access"); + + if(NULL != a->backend_data) + { + pci = (PCIAccess *)(a->backend_data); + check(PCIACCESS_TAG == pci->tag, "pci_access.backend_data already used by alien code"); + } + else + { + pci = pci_malloc(a, sizeof(PCIAccess)); + a->backend_data = pci; + pci->tag = PCIACCESS_TAG; + pci->expansion = (struct ExpansionBase *)IExec->OpenLibrary("expansion.library", 0); + check(NULL != pci->expansion, "Unable to open expansion.library"); + + pci->ipci = (struct PCIIFace *)IExec->GetInterface((struct Library *)pci->expansion, "pci", 1, TAG_DONE); + check(NULL != pci->ipci, "Unable to obtain pci interface"); + } + + return TRUE; + + +on_error: + aos_close_pci_interface(a); + return FALSE; +} + + +static int aos_expansion_detect(struct pci_access *a) +{ + struct PCIDevice *device = NULL; + PCIAccess *pci; + + check(TRUE == aos_open_pci_interface(a), "AmigaOS Expansion PCI interface cannot be accessed."); + pci = a->backend_data; + + // Try to read PCI first device + device = pci->ipci->FindDeviceTags(FDT_Index, 0); + check(NULL != device, "AmigaOS Expansion PCI interface cannot find any device"); + + pci->ipci->FreeDevice(device); + + return TRUE; + +on_error: + aos_close_pci_interface(a); + return FALSE; +} + + +static void aos_expansion_init(struct pci_access *a) +{ + // to avoid flushing of version tag + static STRPTR USED ver = (STRPTR)VERSTAG; + + if (!aos_open_pci_interface(a)) + { + a->debug("\n"); + a->error("AmigaOS Expansion PCI interface cannot be accessed."); + } +} + + +static void aos_expansion_cleanup(struct pci_access *a) +{ + aos_close_pci_interface(a); +} + +/* +#define BYTE_LEN 1 +#define WORD_LEN 2 +#define LONG_LEN 4 +*/ + +static void aos_expansion_scan(struct pci_access *a) +{ + struct PCIDevice *device = NULL; + PCIAccess *pci = NULL; + UBYTE bus_num; + UBYTE dev_num; + UBYTE fn_num; + struct pci_dev *d; + int found_devs = 0; + + check(NULL != a, "Null pci_access"); + pci = a->backend_data; + check((NULL != pci) && (PCIACCESS_TAG == pci->tag), "PCIData struct not available"); + + // 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 + device = pci->ipci->FindDeviceTags(FDT_Index, found_devs); + while(NULL != device) + { + d = pci_alloc_dev(a); + check_mem(d); + d->domain = 0; // only one domain for AmigaOS + device->GetAddress(&bus_num, &dev_num, &fn_num); + d->bus = bus_num; + d->dev = dev_num; + d->func = fn_num; + d->backend_data = device; + d->vendor_id = device->ReadConfigWord(PCI_VENDOR_ID); + d->device_id = device->ReadConfigWord(PCI_DEVICE_ID); + d->known_fields = PCI_FILL_IDENT; + d->hdrtype = device->ReadConfigByte(PCI_HEADER_TYPE) & ~PCI_HEADER_TYPE_MULTIFUNCTION; + pci_link_dev(a, d); + a->debug(" Found device %02x:%02x.%d %04x:%04x\n", d->bus, d->dev, d->func, d->vendor_id, d->device_id); + + found_devs++; + device = pci->ipci->FindDeviceTags(FDT_Index, found_devs); + } + +on_error: + if((NULL != device) && (NULL != pci)) + { + pci->ipci->FreeDevice(device); + } + + return; +} + + +static int aos_expansion_read(struct pci_dev *d, int pos, byte *buf, int len) +{ + byte *ptr = buf; + int i; + + check(NULL != d, "Null pci_dev"); + if(NULL != d->backend_data) + { + for(i = 0; i < len; i++) + { + // byte by byte to avoid endianness troubles + *ptr = ((struct PCIDevice *)(d->backend_data))->ReadConfigByte(pos + i); + ptr++; + } + } + + return TRUE; + +on_error: + return FALSE; +} + + +static int aos_expansion_write(struct pci_dev *d, int pos, byte *buf, int len) +{ + byte *ptr = buf; + int i; + + check(NULL != d, "Null pci_dev"); + if(NULL != d->backend_data) + { + for(i = 0; i < len; i++) + { + // byte by byte to avoid endianness troubles + ((struct PCIDevice *)(d->backend_data))->WriteConfigByte(pos + i, *ptr); + ptr++; + } + } + + return TRUE; + +on_error: + return FALSE; +} + + +static void aos_expansion_init_dev(struct pci_dev *d) +{ + if(NULL != d) + { + d->backend_data = NULL; // struct PCIDevice * to be obtained + } +} + +static void aos_expansion_cleanup_dev(struct pci_dev *d) +{ + PCIAccess *pci; + + if((NULL != d) && (NULL != d->backend_data) && (NULL != d->access) && (NULL != d->access->backend_data)) + { + pci = d->access->backend_data; + pci->ipci->FreeDevice((struct PCIDevice *)d->backend_data); + d->backend_data = NULL; + } +} + + +struct pci_methods pm_aos_expansion = { + "aos-expansion", + "The Expansion.library on AmigaOS 4.x", + NULL, // config, called after allocation of pci_access, if assigned + aos_expansion_detect, // detect, mandatory because called without check + aos_expansion_init, // init, called once access chosen, eventually after detect + aos_expansion_cleanup, // cleanup, called at the end + aos_expansion_scan, // scan, + pci_generic_fill_info, // fill_info, + aos_expansion_read, // read, + aos_expansion_write, // write, + NULL, // read_vpd, + aos_expansion_init_dev, // init_dev, + aos_expansion_cleanup_dev // cleanup_dev, +}; diff --git a/lib/configure b/lib/configure index 158cc0a..8385daa 100755 --- a/lib/configure +++ b/lib/configure @@ -204,6 +204,13 @@ case $sys in IDSDIR="/etc/pci" LIBRESOLV= ;; + amigaos) + echo_n " aos-expansion" + echo >>$c '#define PCI_HAVE_STDINT_H' + echo >>$c '#define PCI_HAVE_PM_AOS_EXPANSION' + IDSDIR="DEVS:" + echo >>$m 'CC=gcc' + ;; *) echo " Unfortunately, your OS is not supported by the PCI Library" exit 1 diff --git a/lib/init.c b/lib/init.c index 3476681..9c805d3 100644 --- a/lib/init.c +++ b/lib/init.c @@ -158,6 +158,11 @@ static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = { #else NULL, #endif +#if defined(PCI_HAVE_PM_AOS_EXPANSION) + &pm_aos_expansion, +#else + NULL, +#endif }; // If PCI_ACCESS_AUTO is selected, we probe the access methods in this order @@ -175,6 +180,7 @@ static int probe_sequence[] = { PCI_ACCESS_WIN32_CFGMGR32, PCI_ACCESS_WIN32_KLDBG, PCI_ACCESS_WIN32_SYSDBG, + PCI_ACCESS_AOS_EXPANSION, // Low-level methods poking the hardware directly PCI_ACCESS_ECAM, PCI_ACCESS_I386_TYPE1, @@ -394,6 +400,30 @@ retry: pci_set_name_list_path(a, path, 1); } } +#elif defined PCI_OS_AMIGAOS + +static void +pci_init_name_list_path(struct pci_access *a) +{ + char last_char; + int len = strlen(PCI_PATH_IDS_DIR); + + if(0 == len) // empty path + { + pci_set_name_list_path(a, PCI_IDS, 0); + } + else + { + last_char = (PCI_PATH_IDS_DIR)[len - 1]; + if((':' == last_char) || ('/' == last_char)) // root or parent char + { + pci_set_name_list_path(a, PCI_PATH_IDS_DIR PCI_IDS, 0); + } + else + { + pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0); + } + } } #else diff --git a/lib/internal.h b/lib/internal.h index 00ac401..ba07d26 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -8,6 +8,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _INTERNAL_H +#define _INTERNAL_H + #include "config.h" #ifdef PCI_SHARED_LIB @@ -139,4 +142,6 @@ extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc, pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device, pm_dump, pm_linux_sysfs, pm_darwin, pm_sylixos_device, pm_hurd, pm_mmio_conf1, pm_mmio_conf1_ext, pm_ecam, - pm_win32_cfgmgr32, pm_win32_kldbg, pm_win32_sysdbg; + pm_win32_cfgmgr32, pm_win32_kldbg, pm_win32_sysdbg, pm_aos_expansion; + +#endif diff --git a/lib/pci.h b/lib/pci.h index 03b4c41..77abdaf 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -51,6 +51,7 @@ enum pci_access_type { PCI_ACCESS_MMIO_TYPE1, /* MMIO ports, type 1 */ PCI_ACCESS_MMIO_TYPE1_EXT, /* MMIO ports, type 1 extended */ PCI_ACCESS_ECAM, /* PCIe ECAM via /dev/mem */ + PCI_ACCESS_AOS_EXPANSION, /* AmigaOS Expansion library */ PCI_ACCESS_MAX }; diff --git a/lib/sysdep.h b/lib/sysdep.h index 7502035..5695c30 100644 --- a/lib/sysdep.h +++ b/lib/sysdep.h @@ -86,6 +86,10 @@ typedef u16 word; #define BYTE_ORDER LITTLE_ENDIAN #endif +#ifdef PCI_OS_AMIGAOS + #include +#endif + #if !defined(BYTE_ORDER) #error "BYTE_ORDER not defined for your platform" #endif