Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: construct driver list at runtime #233

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 0 additions & 34 deletions src/driver_list_start.c

This file was deleted.

34 changes: 0 additions & 34 deletions src/driver_list_stop.c

This file was deleted.

40 changes: 25 additions & 15 deletions src/drivers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Copyright (C) 2016 Lars-Peter Clausen <[email protected]>
* Copyright (C) 2016 Aurelien Jacobs <[email protected]>
* Copyright (C) 2017 Marcus Comstedt <[email protected]>
* Copyright (C) 2023 fenugrec <[email protected]>
*
* 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
Expand All @@ -19,21 +20,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#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.
Expand All @@ -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);
}
55 changes: 34 additions & 21 deletions src/libsigrok-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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);

Expand Down