[PATCH] driver: add Linux struct platform_device/driver compatibility wrapper
Ahmad Fatoum
a.fatoum at pengutronix.de
Tue May 21 01:42:12 PDT 2024
In Linux struct platform_device is a superset on top of struct device with
additions related to specifics of the platform bus.
In barebox, there is no such distinction, so porting of Linux drivers
usually involves a lot of renaming and substitutions.
The naive approach of
#define platform_device device
#define platform_driver driver
won't work though as struct device dev needs to be a member of
platform_device as kernel code has a lot of instances of &pdev->dev.
Therefore, let's tackle this differently:
1) We add struct device as only member of struct platform_device and
define all members in both and have them overlap by use of a union.
2) Have functions that receive a platform_device/driver in Linux, but
a device/driver in barebox accept either by using GCC's transparent
union extension.
More changes are needed, e.g. in <of.h> to use __param_either where
appropriate, but this can be added alongside future kernel driver ports.
The use of __param_either instead of defining the union with a tag and
using that is intentional to keep prototypes self-documenting. This
violates the C standard's strict aliasing rule, but this doesn't matter
for us anyway as we compile barebox with -fno-strict-aliasing.
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
include/device.h | 124 +++++++++++++++++----------------
include/driver.h | 40 ++++++-----
include/linux/compiler_types.h | 11 +++
3 files changed, 98 insertions(+), 77 deletions(-)
diff --git a/include/device.h b/include/device.h
index 8c3561e5a2f6..abe9707fb8f5 100644
--- a/include/device.h
+++ b/include/device.h
@@ -7,6 +7,8 @@
#define DEVICE_H
#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/stddef.h>
enum dev_dma_coherence {
DEV_DMA_COHERENCE_DEFAULT = 0,
@@ -23,83 +25,85 @@ struct platform_device_id;
struct of_device_id;
/** @brief Describes a particular device present in the system */
-struct device {
- /*! This member (and 'type' described below) is used to match
- * with a driver. This is a descriptive name and could be
- * MPC5XXX_ether or imx_serial. Unless absolutely necessary,
- * should not be modified directly and dev_set_name() should
- * be used instead.
- */
- char *name;
+struct platform_device {
+ struct_group_tagged(device, dev,
+ /*! This member (and 'type' described below) is used to match
+ * with a driver. This is a descriptive name and could be
+ * MPC5XXX_ether or imx_serial. Unless absolutely necessary,
+ * should not be modified directly and dev_set_name() should
+ * be used instead.
+ */
+ char *name;
- /*! This member is used to store device's unique name as
- * obtained by calling dev_id(). Internal field, do not
- * access it directly.
- */
- char *unique_name;
- /*! The id is used to uniquely identify a device in the system. The id
- * will show up under /dev/ as the device's name. Usually this is
- * something like eth0 or nor0. */
- int id;
+ /*! This member is used to store device's unique name as
+ * obtained by calling dev_id(). Internal field, do not
+ * access it directly.
+ */
+ char *unique_name;
+ /*! The id is used to uniquely identify a device in the system. The id
+ * will show up under /dev/ as the device's name. Usually this is
+ * something like eth0 or nor0. */
+ int id;
- enum dev_dma_coherence dma_coherent;
+ enum dev_dma_coherence dma_coherent;
- struct resource *resource;
- int num_resources;
+ struct resource *resource;
+ int num_resources;
- void *platform_data; /*! board specific information about this device */
+ void *platform_data; /*! board specific information about this device */
- /*! Devices of a particular class normaly need to store more
- * information than struct device holds.
- */
- void *priv;
- void *type_data; /*! In case this device is a specific device, this pointer
- * points to the type specific device, i.e. eth_device
- */
- struct driver *driver; /*! The driver for this device */
+ /*! Devices of a particular class normaly need to store more
+ * information than struct device holds.
+ */
+ void *priv;
+ void *type_data; /*! In case this device is a specific device, this pointer
+ * points to the type specific device, i.e. eth_device
+ */
+ struct driver *driver; /*! The driver for this device */
- struct list_head list; /* The list of all devices */
- struct list_head bus_list; /* our bus */
- struct list_head children; /* our children */
- struct list_head sibling;
- struct list_head active; /* The list of all devices which have a driver */
+ struct list_head list; /* The list of all devices */
+ struct list_head bus_list; /* our bus */
+ struct list_head children; /* our children */
+ struct list_head sibling;
+ struct list_head active; /* The list of all devices which have a driver */
- struct device *parent; /* our parent, NULL if not present */
+ struct device *parent; /* our parent, NULL if not present */
- struct generic_pm_domain *pm_domain; /* attached power domain */
+ struct generic_pm_domain *pm_domain; /* attached power domain */
- struct bus_type *bus;
+ struct bus_type *bus;
- /*! The parameters for this device. This is used to carry information
- * of board specific data from the board code to the device driver. */
- struct list_head parameters;
+ /*! The parameters for this device. This is used to carry information
+ * of board specific data from the board code to the device driver. */
+ struct list_head parameters;
- struct list_head cdevs;
+ struct list_head cdevs;
- const struct platform_device_id *id_entry;
- union {
- struct device_node *device_node;
- struct device_node *of_node;
- };
+ const struct platform_device_id *id_entry;
+ union {
+ struct device_node *device_node;
+ struct device_node *of_node;
+ };
- const struct of_device_id *of_id_entry;
+ const struct of_device_id *of_id_entry;
- u64 dma_mask;
+ u64 dma_mask;
- unsigned long dma_offset;
+ unsigned long dma_offset;
- void (*info) (struct device *);
- /*
- * For devices which take longer to probe this is called
- * when the driver should actually detect client devices
- */
- int (*detect) (struct device *);
- void (*rescan) (struct device *);
+ void (*info) (struct device *);
+ /*
+ * For devices which take longer to probe this is called
+ * when the driver should actually detect client devices
+ */
+ int (*detect) (struct device *);
+ void (*rescan) (struct device *);
- /*
- * if a driver probe is deferred, this stores the last error
- */
- char *deferred_probe_reason;
+ /*
+ * if a driver probe is deferred, this stores the last error
+ */
+ char *deferred_probe_reason;
+ );
};
struct device_alias {
diff --git a/include/driver.h b/include/driver.h
index c8eb7605e768..9720a76ec2c4 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -10,6 +10,8 @@
#include <linux/ioport.h>
#include <linux/uuid.h>
#include <linux/printk.h>
+#include <linux/compiler.h>
+#include <linux/stddef.h>
#include <device.h>
#include <of.h>
#include <init.h>
@@ -29,27 +31,31 @@ struct platform_device_id {
};
/** @brief Describes a driver present in the system */
-struct driver {
- /*! The name of this driver. Used to match to
- * the corresponding device. */
- const char *name;
+struct platform_driver {
+ struct_group_tagged(driver, drv,
+ /*! The name of this driver. Used to match to
+ * the corresponding device. */
+ const char *name;
- struct list_head list;
- struct list_head bus_list; /* our bus */
+ struct list_head list;
+ struct list_head bus_list; /* our bus */
- /*! Called if an instance of a device is found */
- int (*probe) (struct device *);
+ /*! Called if an instance of a device is found */
+ int (*probe) (__param_either(struct device *,
+ struct platform_driver *));
- /*! Called if an instance of a device is gone. */
- void (*remove)(struct device *);
+ /*! Called if an instance of a device is gone. */
+ void (*remove)(__param_either(struct device *,
+ struct platform_device *));
- struct bus_type *bus;
+ struct bus_type *bus;
- const struct platform_device_id *id_table;
- union {
- const struct of_device_id *of_compatible;
- const struct of_device_id *of_match_table;
- };
+ const struct platform_device_id *id_table;
+ union {
+ const struct of_device_id *of_compatible;
+ const struct of_device_id *of_match_table;
+ };
+ );
};
/*@}*/ /* do not delete, doxygen relevant */
@@ -393,7 +399,7 @@ extern struct list_head bus_list;
extern struct bus_type platform_bus;
-int platform_driver_register(struct driver *drv);
+int platform_driver_register(__param_either(struct driver *, struct platform_driver *));
/* register_driver_macro() - Helper macro for drivers that don't do
* anything special in module registration. This eliminates a lot of
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index d925b3da296d..ae7e615c35a4 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -356,4 +356,15 @@ struct ftrace_likely_data {
#define __prereloc \
notrace __no_sanitize_address __no_stack_protector
+#define __param_oneof(PARAMS) union { \
+ PARAMS; \
+} __attribute__ ((__transparent_union__))
+
+/*
+ * For use in function prototypes. Instructs the compiler to accept either
+ * type1 or type2 as permissible types. The types need to have identical
+ * bit-level representation
+ */
+#define __param_either(type1, type2) __param_oneof(type1 __arg1; type2 __arg2)
+
#endif /* __LINUX_COMPILER_TYPES_H */
--
2.39.2
More information about the barebox
mailing list