summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/settings.c47
-rw-r--r--src/include/ipxe/settings.h1
-rw-r--r--src/tests/settings_test.c10
3 files changed, 58 insertions, 0 deletions
diff --git a/src/core/settings.c b/src/core/settings.c
index b8833c8d5..927ad8459 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/uuid.h>
#include <ipxe/uri.h>
#include <ipxe/base16.h>
+#include <ipxe/pci.h>
#include <ipxe/init.h>
#include <ipxe/settings.h>
@@ -1857,6 +1858,52 @@ struct setting_type setting_type_uuid __setting_type = {
.format = format_uuid_setting,
};
+/**
+ * Parse PCI bus:dev.fn setting value
+ *
+ * @v value Formatted setting value
+ * @v buf Buffer to contain raw value
+ * @v len Length of buffer
+ * @ret len Length of raw value, or negative error
+ */
+static int parse_busdevfn_setting ( const char *value __unused,
+ void *buf __unused, size_t len __unused ) {
+ return -ENOTSUP;
+}
+
+/**
+ * Format PCI bus:dev.fn setting value
+ *
+ * @v raw Raw setting value
+ * @v raw_len Length of raw setting value
+ * @v buf Buffer to contain formatted value
+ * @v len Length of buffer
+ * @ret len Length of formatted value, or negative error
+ */
+static int format_busdevfn_setting ( const void *raw, size_t raw_len, char *buf,
+ size_t len ) {
+ signed long dummy;
+ unsigned long busdevfn;
+ int check_len;
+
+ /* Extract numeric value */
+ check_len = numeric_setting_value ( raw, raw_len, &dummy, &busdevfn );
+ if ( check_len < 0 )
+ return check_len;
+ assert ( check_len == ( int ) raw_len );
+
+ /* Format value */
+ return snprintf ( buf, len, "%02lx:%02lx.%lx", PCI_BUS ( busdevfn ),
+ PCI_SLOT ( busdevfn ), PCI_FUNC ( busdevfn ) );
+}
+
+/** PCI bus:dev.fn setting type */
+struct setting_type setting_type_busdevfn __setting_type = {
+ .name = "busdevfn",
+ .parse = parse_busdevfn_setting,
+ .format = format_busdevfn_setting,
+};
+
/******************************************************************************
*
* Setting expansion
diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h
index 7ceb55ca5..8ee9516ec 100644
--- a/src/include/ipxe/settings.h
+++ b/src/include/ipxe/settings.h
@@ -324,6 +324,7 @@ extern struct setting_type setting_type_hex __setting_type;
extern struct setting_type setting_type_hexhyp __setting_type;
extern struct setting_type setting_type_hexraw __setting_type;
extern struct setting_type setting_type_uuid __setting_type;
+extern struct setting_type setting_type_busdevfn __setting_type;
extern struct setting ip_setting __setting ( SETTING_IPv4 );
extern struct setting netmask_setting __setting ( SETTING_IPv4 );
diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c
index d6d125748..42957c7d7 100644
--- a/src/tests/settings_test.c
+++ b/src/tests/settings_test.c
@@ -182,6 +182,12 @@ static struct setting test_uuid_setting = {
.type = &setting_type_uuid,
};
+/** Test PCI bus:dev.fn setting type */
+static struct setting test_busdevfn_setting = {
+ .name = "test_busdevfn",
+ .type = &setting_type_busdevfn,
+};
+
/**
* Perform settings self-tests
*
@@ -282,6 +288,10 @@ static void settings_test_exec ( void ) {
0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ),
"1a6a749d-0eda-461a-a87a-7cfe4fca4a57" );
+ /* "busdevfn" setting type (no store capability) */
+ fetchf_ok ( &test_settings, &test_busdevfn_setting,
+ RAW ( 0x03, 0x45 ), "03:08.5" );
+
/* Clear and unregister test settings block */
clear_settings ( &test_settings );
unregister_settings ( &test_settings );