diff --git a/src/core/settings.c b/src/core/settings.c index b8833c8d..927ad845 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include @@ -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 7ceb55ca..8ee9516e 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 d6d12574..42957c7d 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 );