diff --git a/Makefile.am b/Makefile.am index 62aca8ac9..245157142 100644 --- a/Makefile.am +++ b/Makefile.am @@ -216,22 +216,16 @@ libsigrok_la_SOURCES += \ src/scale/kern.c # Hardware drivers -noinst_LTLIBRARIES = src/libdrivers.la \ - src/libdrivers_head.la src/libdrivers_tail.la +noinst_LTLIBRARIES = src/libdrivers.la + +src/libdrivers.o: src/libdrivers.la + $(AM_V_CCLD)$(LINK) src/libdrivers.la -src/libdrivers.o: src/libdrivers.la \ - src/libdrivers_head.la src/libdrivers_tail.la - $(AM_V_CCLD)$(LINK) src/libdrivers_head.la src/libdrivers.la \ - src/libdrivers_tail.la src/libdrivers.lo: src/libdrivers.o $(AM_V_GEN)echo "# Generated by libtool" > $@ $(AM_V_at)echo "pic_object='libdrivers.o'" >> $@ $(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@ -src_libdrivers_head_la_SOURCES = src/driver_list_start.c - -src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c - src_libdrivers_la_SOURCES = src/drivers.c if HW_AGILENT_DMM diff --git a/src/driver_list_start.c b/src/driver_list_start.c deleted file mode 100644 index 535e33122..000000000 --- a/src/driver_list_start.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2017 Marcus Comstedt - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "libsigrok-internal.h" - -/* - * This marks the start of the driver list. This file must be linked - * before any actual drivers. - */ - -SR_PRIV const struct sr_dev_driver *sr_driver_list__start[] - SR_DRIVER_LIST_NOREORDER - __attribute__((section (SR_DRIVER_LIST_SECTION), - used, aligned(sizeof(struct sr_dev_driver *)))) - = { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ }; diff --git a/src/driver_list_stop.c b/src/driver_list_stop.c deleted file mode 100644 index eefda0559..000000000 --- a/src/driver_list_stop.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2017 Marcus Comstedt - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "libsigrok-internal.h" - -/* - * This marks the end of the driver list. This file must be linked - * after any actual drivers. - */ - -SR_PRIV const struct sr_dev_driver *sr_driver_list__stop[] - SR_DRIVER_LIST_NOREORDER - __attribute__((section (SR_DRIVER_LIST_SECTION), - used, aligned(sizeof(struct sr_dev_driver *)))) - = { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ }; diff --git a/src/drivers.c b/src/drivers.c index 6dc2c55cb..d0f70d4db 100644 --- a/src/drivers.c +++ b/src/drivers.c @@ -4,6 +4,7 @@ * Copyright (C) 2016 Lars-Peter Clausen * Copyright (C) 2016 Aurelien Jacobs * Copyright (C) 2017 Marcus Comstedt + * Copyright (C) 2023 fenugrec * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,21 +20,32 @@ * along with this program. If not, see . */ -#include #include #include #include "libsigrok-internal.h" -/* - * The special __sr_driver_list section contains pointers to all hardware - * drivers which were built into the library according to its configuration - * (will depend on the availability of dependencies, as well as user provided - * specs). The __start and __stop symbols point to the start and end of the - * section. They are used to iterate over the list of all drivers which were - * included in the library. +static struct device_node *devlist_head = NULL; + +/* constructors will call this, before main() and GLib init. + * We only assume static variables were initialized (i.e. contents of .bss + * and .data sections). */ -SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[]; -SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[]; +void sr_register_dev_node(struct device_node *devnode) { + devnode->next = devlist_head; + devlist_head = devnode; +} + +void sr_register_dev_array(struct sr_dev_driver * const driver_array[], struct device_node *node_array, unsigned num) { + unsigned i; + struct device_node *dnode; + + for (i = 0; i < num; i++) { + dnode = &node_array[i]; + dnode->dev = driver_array[i]; + sr_register_dev_node(dnode); + } +} + /** * Initialize the driver list in a fresh libsigrok context. @@ -47,10 +59,8 @@ SR_API void sr_drivers_init(struct sr_context *ctx) GArray *array; array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *)); -#ifdef HAVE_DRIVERS - for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1; - drivers < sr_driver_list__stop; drivers++) - g_array_append_val(array, *drivers); -#endif + for (struct device_node *cur = devlist_head; cur; cur = cur->next) { + g_array_append_val(array, cur->dev); + } ctx->driver_list = (struct sr_dev_driver **)g_array_free(array, FALSE); } diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 68a45f277..2795bb8c3 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1127,20 +1127,28 @@ static inline void write_dblle_inc(uint8_t **p, double x) #define ALL_ZERO { 0 } #endif -#ifdef __APPLE__ -#define SR_DRIVER_LIST_SECTION "__DATA,__sr_driver_list" -#else -#define SR_DRIVER_LIST_SECTION "__sr_driver_list" -#endif -#if !defined SR_DRIVER_LIST_NOREORDER && defined __has_attribute -#if __has_attribute(no_reorder) -#define SR_DRIVER_LIST_NOREORDER __attribute__((no_reorder)) -#endif -#endif -#if !defined SR_DRIVER_LIST_NOREORDER -#define SR_DRIVER_LIST_NOREORDER /* EMPTY */ -#endif +/* constructors will assemble a LL with every driver. + * Every driver defines one of these struct by using one of the + * SR_REGISTER_DEV_DRIVER_* macros below. + * This could be greatly simplified if struct sr_dev_driver had a '->next' member. Maybe someday. +*/ +struct device_node { + struct sr_dev_driver *dev; + struct device_node *next; +}; + +/** should only be called via SR_REGISTER_DEV_DRIVER_LIST() macro */ +void sr_register_dev_array(struct sr_dev_driver * const driver_array[], struct device_node *node_array, unsigned num); + +/** should only be called via SR_REGISTER_DEV_DRIVER() macro */ +void sr_register_dev_node(struct device_node *devnode); + + +/* glib uses this internally but doesn't seem to make it available. + * This is a much simplified def that will only work on gcc/clang. + */ +#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void); /** * Register a list of hardware drivers. @@ -1170,13 +1178,14 @@ static inline void write_dblle_inc(uint8_t **p, double x) * @param ... Comma separated list of pointers to sr_dev_driver structs. */ #define SR_REGISTER_DEV_DRIVER_LIST(name, ...) \ - static const struct sr_dev_driver *name[] \ - SR_DRIVER_LIST_NOREORDER \ - __attribute__((section (SR_DRIVER_LIST_SECTION), used, \ - aligned(sizeof(struct sr_dev_driver *)))) \ - = { \ - __VA_ARGS__ \ - }; + static struct sr_dev_driver * const name[] = { \ + __VA_ARGS__ \ + }; \ + static struct device_node name##_nodes[ARRAY_SIZE(name)]; \ + G_DEFINE_CONSTRUCTOR(register_##name) \ + static void register_##name(void) { \ + sr_register_dev_array(name, name##_nodes, ARRAY_SIZE(name)); \ + } /** * Register a hardware driver. @@ -1200,7 +1209,11 @@ static inline void write_dblle_inc(uint8_t **p, double x) * @param name Identifier name of sr_dev_driver struct to register. */ #define SR_REGISTER_DEV_DRIVER(name) \ - SR_REGISTER_DEV_DRIVER_LIST(name##_list, &name); + static struct device_node name##_node = { .dev = &name }; \ + G_DEFINE_CONSTRUCTOR(register_##name) \ + static void register_##name(void) { \ + sr_register_dev_node(&name##_node); \ + } SR_API void sr_drivers_init(struct sr_context *context);