├── .gitignore ├── .linter-ignore ├── LICENSE ├── Makefile ├── Makefile.python ├── OWNERS ├── bmcctl ├── Makefile └── control_bmc_obj.c ├── configs ├── Barreleye.py ├── Firestone.py ├── Garrison.py ├── Lanyang.py ├── Palmetto.py ├── Romulus.py ├── S2600wf.py ├── Witherspoon.py └── Zaius.py ├── fanctl ├── Makefile └── fan_control.c ├── flashbios ├── Makefile └── flash_bios_obj.c ├── gdbus.mk ├── ledctl ├── Makefile └── led_controller.c ├── libopenbmc_intf ├── GPIOS.md ├── Makefile ├── codegen ├── gpio.c ├── gpio.h ├── gpio_configs.c ├── gpio_configs.h ├── gpio_json.c ├── gpio_json.h ├── meson.build ├── openbmc.h ├── openbmc_intf.c ├── openbmc_intf.h └── openbmc_intf.xml ├── meson.build ├── op-flasher ├── Makefile └── flasher_obj.c ├── op-hostctl ├── Makefile ├── control_host_obj.c └── meson.build ├── op-pwrctl ├── Makefile ├── meson.build ├── pgood_wait │ ├── .gitignore │ ├── Makefile │ ├── meson.build │ └── pgood_wait.c └── power_control_obj.c ├── py.mk ├── pychassisctl ├── Makefile ├── chassis_control.py ├── setup.cfg └── setup.py ├── pydownloadmgr ├── Makefile ├── download_manager.py ├── setup.cfg └── setup.py ├── pyflashbmc ├── Makefile ├── bmc_update.py ├── setup.cfg └── setup.py ├── pyinventorymgr ├── Makefile ├── inventory_items.py ├── obmc │ └── inventory │ │ └── __init__.py ├── setup.cfg ├── setup.py └── sync_inventory_items.py ├── pyipmitest ├── Makefile ├── ipmi_debug.py ├── setup.cfg └── setup.py ├── pystatemgr ├── Makefile ├── discover_system_state.py ├── setup.cfg └── setup.py ├── pysystemmgr ├── Makefile ├── obmc │ └── system │ │ └── __init__.py ├── setup.cfg ├── setup.py └── system_manager.py ├── pytools ├── Makefile ├── gpioutil ├── setup.cfg └── setup.py ├── rules.mk ├── sdbus.mk ├── setup.cfg └── subprojects └── cjson.wrap /.gitignore: -------------------------------------------------------------------------------- 1 | /build*/ 2 | /subprojects/* 3 | !/subprojects/*.wrap 4 | 5 | *.exe 6 | *.o 7 | *.so 8 | *.so.* 9 | *.swp 10 | *.swo 11 | */build 12 | -------------------------------------------------------------------------------- /.linter-ignore: -------------------------------------------------------------------------------- 1 | configs/Lanyang.py 2 | configs/Witherspoon.py 3 | configs/Zaius.py 4 | pyflashbmc/bmc_update.py 5 | pyinventorymgr/inventory_items.py 6 | pyinventorymgr/sync_inventory_items.py 7 | pyipmitest/ipmi_debug.py 8 | pysystemmgr/system_manager.py 9 | pytools/gpioutil 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GDBUS_APPS = bmcctl \ 2 | flashbios \ 3 | op-flasher \ 4 | op-hostctl \ 5 | op-pwrctl 6 | 7 | SUBDIRS = fanctl \ 8 | ledctl \ 9 | libopenbmc_intf \ 10 | pychassisctl \ 11 | pydownloadmgr \ 12 | pyflashbmc \ 13 | pyinventorymgr \ 14 | pyipmitest \ 15 | pystatemgr \ 16 | pysystemmgr \ 17 | pytools 18 | 19 | REVERSE_SUBDIRS = $(shell echo $(SUBDIRS) $(GDBUS_APPS) | tr ' ' '\n' | tac |tr '\n' ' ') 20 | 21 | .PHONY: subdirs $(SUBDIRS) $(GDBUS_APPS) 22 | 23 | subdirs: $(SUBDIRS) $(GDBUS_APPS) 24 | 25 | $(SUBDIRS): 26 | $(MAKE) -C $@ 27 | 28 | $(GDBUS_APPS): libopenbmc_intf 29 | $(MAKE) -C $@ CFLAGS="-I ../$^" LDFLAGS="-L ../$^" 30 | 31 | install: subdirs 32 | @for d in $(SUBDIRS) $(GDBUS_APPS); do \ 33 | $(MAKE) -C $$d $@ DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) || exit 1; \ 34 | done 35 | clean: 36 | @for d in $(REVERSE_SUBDIRS); do \ 37 | $(MAKE) -C $$d $@ || exit 1; \ 38 | done 39 | -------------------------------------------------------------------------------- /Makefile.python: -------------------------------------------------------------------------------- 1 | include ../py.mk 2 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # OWNERS 2 | # ------ 3 | # 4 | # The OWNERS file maintains the list of individuals responsible for various 5 | # parts of this repository, including code review and approval. We use the 6 | # Gerrit 'owners' plugin, which consumes this file, along with some extra 7 | # keywords for our own purposes and tooling. 8 | # 9 | # For details on the configuration used by 'owners' see: 10 | # https://gerrit.googlesource.com/plugins/owners/+/refs/heads/master/owners/src/main/resources/Documentation/config.md 11 | # 12 | # An OWNERS file must be in the root of a repository but may also be present 13 | # in any subdirectory. The contents of the subdirectory OWNERS file are 14 | # combined with parent directories unless 'inherit: false' is set. 15 | # 16 | # The owners file is YAML and has [up to] 4 top-level keywords. 17 | # * owners: A list of individuals who have approval authority on the 18 | # repository. 19 | # 20 | # * reviewers: A list of individuals who have requested review notification 21 | # on the repository. 22 | # 23 | # * matchers: A list of specific file/path matchers for granular 'owners' and 24 | # 'reviewers'. See 'owners' plugin documentation. 25 | # 26 | # * openbmc: A list of openbmc-specific meta-data about owners and reviewers. 27 | # - name: preferred name of the individual. 28 | # - email: preferred email address of the individual. 29 | # - discord: Discord nickname of the individual. 30 | # 31 | # It is expected that these 4 sections will be listed in the order above and 32 | # data within them will be kept sorted. 33 | 34 | owners: 35 | - anoo@us.ibm.com 36 | - joel@jms.id.au 37 | 38 | reviewers: 39 | 40 | matchers: 41 | 42 | openbmc: 43 | - name: Adriana Kobylak 44 | email: anoo@us.ibm.com 45 | discord: anoo 46 | - name: Joel Stanley 47 | email: joel@jms.id.au 48 | discord: joel 49 | -------------------------------------------------------------------------------- /bmcctl/Makefile: -------------------------------------------------------------------------------- 1 | BINS=control_bmc 2 | include ../gdbus.mk 3 | include ../rules.mk 4 | -------------------------------------------------------------------------------- /bmcctl/control_bmc_obj.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* ------------------------------------------------------------------------- */ 8 | static const gchar* dbus_object_path = "/org/openbmc/control"; 9 | static const gchar* instance_name = "bmc0"; 10 | static const gchar* dbus_name = "org.openbmc.control.Bmc"; 11 | 12 | static GDBusObjectManagerServer *manager = NULL; 13 | 14 | static gboolean on_init(Control *control, GDBusMethodInvocation *invocation, 15 | gpointer user_data) 16 | { 17 | control_complete_init(control, invocation); 18 | return TRUE; 19 | } 20 | 21 | static gboolean on_warm_reset(ControlBmc *bmc, 22 | GDBusMethodInvocation *invocation, 23 | gpointer user_data) 24 | { 25 | /* Wait a while before reboot, so the caller can be responded. 26 | */ 27 | const char *reboot_command = "/bin/sh -c 'sleep 3;reboot'&"; 28 | if(system(reboot_command) < 0){ 29 | return FALSE; 30 | } 31 | 32 | control_bmc_complete_warm_reset(bmc, invocation); 33 | return TRUE; 34 | } 35 | 36 | static gboolean on_cold_reset(ControlBmc *bmc, 37 | GDBusMethodInvocation *invocation, 38 | gpointer user_data) 39 | { 40 | GError *err = NULL; 41 | /* Wait a while before reboot, so the caller can be responded. 42 | * Note that g_spawn_command_line_async() cannot parse ';' as 43 | * a command separator. Need to use 'sh -c' to let shell parse it. 44 | */ 45 | gchar *reboot_command = "/bin/sh -c 'sleep 3;reboot'"; 46 | 47 | g_spawn_command_line_async(reboot_command, &err); 48 | if(err != NULL) { 49 | fprintf(stderr, "coldReset() error: %s\n", err->message); 50 | g_error_free(err); 51 | } 52 | 53 | control_bmc_complete_cold_reset(bmc, invocation); 54 | return TRUE; 55 | } 56 | 57 | static void on_bus_acquired(GDBusConnection *connection, const gchar *name, 58 | gpointer user_data) 59 | { 60 | ObjectSkeleton *object; 61 | cmdline *cmd = user_data; 62 | manager = g_dbus_object_manager_server_new(dbus_object_path); 63 | 64 | gchar *s; 65 | s = g_strdup_printf("%s/%s", dbus_object_path, instance_name); 66 | object = object_skeleton_new(s); 67 | g_free(s); 68 | 69 | ControlBmc* control_bmc = control_bmc_skeleton_new(); 70 | object_skeleton_set_control_bmc(object, control_bmc); 71 | g_object_unref(control_bmc); 72 | 73 | Control* control = control_skeleton_new(); 74 | object_skeleton_set_control(object, control); 75 | g_object_unref(control); 76 | 77 | //define method callbacks here 78 | g_signal_connect(control, "handle-init", G_CALLBACK(on_init), NULL); /* user_data */ 79 | 80 | g_signal_connect(control_bmc, "handle-warm-reset", 81 | G_CALLBACK(on_warm_reset), NULL); /* user_data */ 82 | 83 | g_signal_connect(control_bmc, "handle-cold-reset", 84 | G_CALLBACK(on_cold_reset), NULL); /* user_data */ 85 | 86 | /* Export the object (@manager takes its own reference to @object) */ 87 | g_dbus_object_manager_server_export(manager, 88 | G_DBUS_OBJECT_SKELETON(object)); 89 | g_object_unref(object); 90 | 91 | /* Export all objects */ 92 | g_dbus_object_manager_server_set_connection(manager, connection); 93 | 94 | cmd->user_data = object; 95 | } 96 | 97 | static void on_name_acquired(GDBusConnection *connection, const gchar *name, 98 | gpointer user_data) 99 | { 100 | } 101 | 102 | static void on_name_lost(GDBusConnection *connection, const gchar *name, 103 | gpointer user_data) 104 | { 105 | } 106 | 107 | /*----------------------------------------------------------------*/ 108 | /* Main Event Loop */ 109 | 110 | gint main(gint argc, gchar *argv[]) 111 | { 112 | GMainLoop *loop; 113 | cmdline cmd; 114 | cmd.argc = argc; 115 | cmd.argv = argv; 116 | 117 | guint id; 118 | loop = g_main_loop_new(NULL, FALSE); 119 | cmd.loop = loop; 120 | 121 | id = g_bus_own_name( 122 | DBUS_TYPE, 123 | dbus_name, 124 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT 125 | | G_BUS_NAME_OWNER_FLAGS_REPLACE, 126 | on_bus_acquired, on_name_acquired, on_name_lost, &cmd, NULL); 127 | 128 | g_main_loop_run(loop); 129 | 130 | g_bus_unown_name(id); 131 | g_main_loop_unref(loop); 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /configs/Palmetto.py: -------------------------------------------------------------------------------- 1 | # System states 2 | # state can change to next state in 2 ways: 3 | # - a process emits a GotoSystemState signal with state name to goto 4 | # - objects specified in EXIT_STATE_DEPEND have started 5 | SYSTEM_STATES = [ 6 | "BASE_APPS", 7 | "BMC_STARTING", 8 | "BMC_READY", 9 | "HOST_POWERING_ON", 10 | "HOST_POWERED_ON", 11 | "HOST_BOOTING", 12 | "HOST_BOOTED", 13 | "HOST_POWERED_OFF", 14 | ] 15 | 16 | EXIT_STATE_DEPEND = { 17 | "BASE_APPS": { 18 | "/org/openbmc/sensors": 0, 19 | }, 20 | "BMC_STARTING": { 21 | "/org/openbmc/control/chassis0": 0, 22 | "/org/openbmc/control/power0": 0, 23 | "/org/openbmc/control/led/identify": 0, 24 | "/org/openbmc/control/host0": 0, 25 | "/org/openbmc/control/flash/bios": 0, 26 | }, 27 | } 28 | 29 | ID_LOOKUP = { 30 | "FRU": { 31 | 0x0D: "/system/chassis", 32 | 0x34: "/system/chassis/motherboard", 33 | 0x01: "/system/chassis/motherboard/cpu", 34 | 0x02: "/system/chassis/motherboard/membuf", 35 | 0x03: "/system/chassis/motherboard/dimm0", 36 | 0x04: "/system/chassis/motherboard/dimm1", 37 | 0x05: "/system/chassis/motherboard/dimm2", 38 | 0x06: "/system/chassis/motherboard/dimm3", 39 | 0x35: "/system", 40 | }, 41 | "FRU_STR": { 42 | "PRODUCT_15": "/system", 43 | "CHASSIS_2": "/system/chassis", 44 | "BOARD_1": "/system/chassis/motherboard/cpu", 45 | "BOARD_2": "/system/chassis/motherboard/membuf", 46 | "BOARD_14": "/system/chassis/motherboard", 47 | "PRODUCT_3": "/system/chassis/motherboard/dimm0", 48 | "PRODUCT_4": "/system/chassis/motherboard/dimm1", 49 | "PRODUCT_5": "/system/chassis/motherboard/dimm2", 50 | "PRODUCT_6": "/system/chassis/motherboard/dimm3", 51 | }, 52 | "SENSOR": { 53 | 0x34: "/system/chassis/motherboard", 54 | 0x37: "/system/chassis/motherboard/refclock", 55 | 0x38: "/system/chassis/motherboard/pcieclock", 56 | 0x39: "/system/chassis/motherboard/todclock", 57 | 0x3A: "/system/chassis/apss", 58 | 0x2F: "/system/chassis/motherboard/cpu", 59 | 0x22: "/system/chassis/motherboard/cpu/core1", 60 | 0x23: "/system/chassis/motherboard/cpu/core2", 61 | 0x24: "/system/chassis/motherboard/cpu/core3", 62 | 0x25: "/system/chassis/motherboard/cpu/core4", 63 | 0x26: "/system/chassis/motherboard/cpu/core5", 64 | 0x27: "/system/chassis/motherboard/cpu/core6", 65 | 0x28: "/system/chassis/motherboard/cpu/core9", 66 | 0x29: "/system/chassis/motherboard/cpu/core10", 67 | 0x2A: "/system/chassis/motherboard/cpu/core11", 68 | 0x2B: "/system/chassis/motherboard/cpu/core12", 69 | 0x2C: "/system/chassis/motherboard/cpu/core13", 70 | 0x2D: "/system/chassis/motherboard/cpu/core14", 71 | 0x2E: "/system/chassis/motherboard/membuf", 72 | 0x1E: "/system/chassis/motherboard/dimm0", 73 | 0x1F: "/system/chassis/motherboard/dimm1", 74 | 0x20: "/system/chassis/motherboard/dimm2", 75 | 0x21: "/system/chassis/motherboard/dimm3", 76 | 0x09: "/org/openbmc/sensors/host/BootCount", 77 | 0x05: "/org/openbmc/sensors/host/BootProgress", 78 | 0x32: "/org/openbmc/sensors/host/OperatingSystemStatus", 79 | }, 80 | "GPIO_PRESENT": { 81 | "SLOT0_PRESENT": ( 82 | "/system/chassis/motherboard/pciecard_x16" 83 | ), 84 | "SLOT1_PRESENT": ( 85 | "/system/chassis/motherboard/pciecard_x8" 86 | ), 87 | }, 88 | } 89 | 90 | # Miscellaneous non-poll sensor with system specific properties. 91 | # The sensor id is the same as those defined in ID_LOOKUP['SENSOR']. 92 | MISC_SENSORS = {} 93 | -------------------------------------------------------------------------------- /configs/S2600wf.py: -------------------------------------------------------------------------------- 1 | # System states 2 | # state can change to next state in 2 ways: 3 | # - a process emits a GotoSystemState signal with state name to goto 4 | # - objects specified in EXIT_STATE_DEPEND have started 5 | SYSTEM_STATES = [] 6 | 7 | FRU_INSTANCES = { 8 | "/system/chassis/motherboard/bmc": { 9 | "fru_type": "BMC", 10 | "is_fru": False, 11 | "manufacturer": "ASPEED", 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /fanctl/Makefile: -------------------------------------------------------------------------------- 1 | BINS=fan_control 2 | include ../sdbus.mk 3 | include ../rules.mk 4 | -------------------------------------------------------------------------------- /fanctl/fan_control.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2016 IBM Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define DBUS_MAX_NAME_LEN 256 25 | 26 | const char *objectmapper_service_name = "xyz.openbmc_project.ObjectMapper"; 27 | const char *objectmapper_object_name = "/xyz/openbmc_project/object_mapper"; 28 | const char *objectmapper_intf_name = "xyz.openbmc_project.ObjectMapper"; 29 | 30 | typedef struct { 31 | int fan_num; 32 | int cpu_num; 33 | int core_num; 34 | int dimm_num; 35 | sd_bus *bus; 36 | char sensor_service[DBUS_MAX_NAME_LEN]; 37 | char inventory_service[DBUS_MAX_NAME_LEN]; 38 | } fan_info_t; 39 | 40 | /* Get an object's bus name from ObjectMapper */ 41 | int get_connection(sd_bus *bus, char *connection, const char *obj_path) 42 | { 43 | sd_bus_error bus_error = SD_BUS_ERROR_NULL; 44 | sd_bus_message *m = NULL; 45 | char *temp_buf = NULL, *intf = NULL; 46 | int rc; 47 | 48 | rc = sd_bus_call_method(bus, 49 | objectmapper_service_name, 50 | objectmapper_object_name, 51 | objectmapper_intf_name, 52 | "GetObject", 53 | &bus_error, 54 | &m, 55 | "ss", 56 | obj_path, 57 | ""); 58 | if (rc < 0) { 59 | fprintf(stderr, 60 | "Failed to GetObject: %s\n", bus_error.message); 61 | goto finish; 62 | } 63 | 64 | /* Get the key, aka, the bus name */ 65 | sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf); 66 | strncpy(connection, temp_buf, DBUS_MAX_NAME_LEN); 67 | 68 | finish: 69 | sd_bus_error_free(&bus_error); 70 | sd_bus_message_unref(m); 71 | sd_bus_flush(bus); 72 | 73 | return rc; 74 | } 75 | 76 | 77 | int set_dbus_sensor(sd_bus *bus, const char *obj_path, int val) 78 | { 79 | char connection[DBUS_MAX_NAME_LEN]; 80 | sd_bus_error bus_error = SD_BUS_ERROR_NULL; 81 | sd_bus_message *response = NULL; 82 | int rc; 83 | 84 | if (!bus || !obj_path) 85 | return -1; 86 | 87 | rc = get_connection(bus, connection, obj_path); 88 | if (rc < 0) { 89 | fprintf(stderr, 90 | "fanctl: Failed to get bus name for %s\n", obj_path); 91 | goto finish; 92 | } 93 | 94 | rc = sd_bus_set_property(bus, 95 | connection, 96 | obj_path, 97 | "xyz.openbmc_project.Control.FanSpeed", 98 | "Target", 99 | &bus_error, 100 | "i", 101 | val); 102 | if (rc < 0) 103 | fprintf(stderr, 104 | "fanctl: Failed to set sensor %s:[%s]\n", 105 | obj_path, strerror(-rc)); 106 | 107 | finish: 108 | sd_bus_error_free(&bus_error); 109 | sd_bus_message_unref(response); 110 | sd_bus_flush(bus); 111 | 112 | return rc; 113 | } 114 | 115 | /* Read sensor value from "xyz.openbmc_projects.Sensors" */ 116 | int read_dbus_sensor(sd_bus *bus, const char *obj_path, const char *property) 117 | { 118 | char connection[DBUS_MAX_NAME_LEN]; 119 | sd_bus_error bus_error = SD_BUS_ERROR_NULL; 120 | sd_bus_message *response = NULL; 121 | int rc; 122 | int val = 0; 123 | 124 | if (!bus || !obj_path) 125 | return 0; 126 | 127 | rc = get_connection(bus, connection, obj_path); 128 | if (rc < 0) { 129 | val = 0; 130 | fprintf(stderr, 131 | "fanctl: Failed to get bus name for %s\n", obj_path); 132 | goto finish; 133 | } 134 | 135 | rc = sd_bus_get_property(bus, 136 | connection, 137 | obj_path, 138 | "xyz.openbmc_project.Sensor.Value", 139 | property, 140 | &bus_error, 141 | &response, 142 | "i"); 143 | if (rc < 0) { 144 | val = 0; 145 | fprintf(stderr, 146 | "fanctl: Failed to read sensor value from %s:[%s]\n", 147 | obj_path, strerror(-rc)); 148 | goto finish; 149 | } 150 | 151 | rc = sd_bus_message_read(response, "i", &val); 152 | if (rc < 0) { 153 | val = 0; 154 | fprintf(stderr, 155 | "fanctl: Failed to parse sensor value " 156 | "response message from %s:[%s]\n", 157 | obj_path, strerror(-rc)); 158 | } 159 | 160 | finish: 161 | sd_bus_error_free(&bus_error); 162 | sd_bus_message_unref(response); 163 | sd_bus_flush(bus); 164 | 165 | return val; 166 | } 167 | 168 | /* set fan speed with /xyz/openbmc_project/sensors/fan_tach/fan* object */ 169 | static int fan_set_speed(sd_bus *bus, int fan_id, uint8_t fan_speed) 170 | { 171 | char obj_path[DBUS_MAX_NAME_LEN]; 172 | int rc; 173 | 174 | if (!bus) 175 | return -1; 176 | 177 | snprintf(obj_path, sizeof(obj_path), 178 | "/xyz/openbmc_project/sensors/fan_tach/fan%d_0", fan_id); 179 | rc = set_dbus_sensor(bus, obj_path, fan_speed); 180 | if (rc < 0) 181 | fprintf(stderr, "fanctl: Failed to set fan[%d] speed[%d]\n", 182 | fan_id, fan_speed); 183 | 184 | return rc; 185 | } 186 | 187 | static int fan_set_max_speed(fan_info_t *info) 188 | { 189 | int i; 190 | int rc = -1; 191 | 192 | if (!info) 193 | return -1; 194 | for (i = 0; i < info->fan_num; i++) { 195 | rc = fan_set_speed(info->bus, i, 255); 196 | if (rc < 0) 197 | break; 198 | fprintf(stderr, "fanctl: Set fan%d to max speed\n", i); 199 | } 200 | 201 | return rc; 202 | } 203 | /* 204 | * FAN_TACH_OFFSET is specific to Barreleye. 205 | * Barreleye uses NTC7904D HW Monitor as Fan tachometoer. 206 | * The 13-bit FANIN value is made up Higher part: [12:5], 207 | * and Lower part: [4:0], which are read from two sensors. 208 | * see: https://www.nuvoton.com/resource-files/NCT7904D_Datasheet_V1.44.pdf 209 | */ 210 | #define FAN_TACH_OFFSET 5 211 | static int fan_get_speed(sd_bus *bus, int fan_id) 212 | { 213 | int fan_tach_H = 0, fan_tach_L = 0; 214 | char obj_path[DBUS_MAX_NAME_LEN]; 215 | int fan_speed; 216 | 217 | /* get fan tach */ 218 | snprintf(obj_path, sizeof(obj_path), 219 | "/xyz/openbmc_project/sensors/fan_tach/fan%d_0", fan_id); 220 | fan_tach_H = read_dbus_sensor(bus, obj_path, "MaxValue"); 221 | fan_tach_L = read_dbus_sensor(bus, obj_path, "MinValue"); 222 | 223 | /* invalid sensor value is -1 */ 224 | if (fan_tach_H <= 0 || fan_tach_L <= 0) 225 | fan_speed = 0; 226 | else 227 | fan_speed = fan_tach_H << FAN_TACH_OFFSET | fan_tach_L; 228 | 229 | fprintf(stderr, "fan%d speed: %d\n", fan_id, fan_speed); 230 | return fan_speed; 231 | } 232 | 233 | /* set Fan Inventory 'Present' status */ 234 | int fan_set_present(sd_bus *bus, int fan_id, int val) 235 | { 236 | sd_bus_error bus_error = SD_BUS_ERROR_NULL; 237 | sd_bus_message *response = NULL; 238 | int rc; 239 | char obj_path[DBUS_MAX_NAME_LEN]; 240 | char connection[DBUS_MAX_NAME_LEN]; 241 | 242 | snprintf(obj_path, sizeof(obj_path), 243 | "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan%d", 244 | fan_id); 245 | 246 | rc = get_connection(bus, connection, obj_path); 247 | if (rc < 0) { 248 | fprintf(stderr, 249 | "fanctl: Failed to get bus name for %s\n", obj_path); 250 | goto finish; 251 | } 252 | 253 | rc = sd_bus_set_property(bus, 254 | connection, 255 | obj_path, 256 | "xyz.openbmc_project.Inventory.Item", 257 | "Present", 258 | &bus_error, 259 | "b", 260 | val); 261 | if(rc < 0) 262 | fprintf(stderr, 263 | "fanctl: Failed to update fan presence via dbus: %s\n", 264 | bus_error.message); 265 | 266 | fprintf(stderr, "fanctl: Set fan%d present status to: %s\n", 267 | fan_id, (val == 1 ? "True" : "False")); 268 | 269 | finish: 270 | sd_bus_error_free(&bus_error); 271 | sd_bus_message_unref(response); 272 | sd_bus_flush(bus); 273 | 274 | return rc; 275 | } 276 | 277 | /* 278 | * Update Fan Invertory 'Present' status by first reading fan speed. 279 | * If fan speed is '0', the fan is considerred not 'Present'. 280 | */ 281 | static int fan_update_present(fan_info_t *info) 282 | { 283 | int i; 284 | int rc = -1; 285 | int fan_speed; 286 | 287 | if (!info) 288 | return -1; 289 | 290 | for (i = 0; i < info->fan_num; i++) { 291 | fan_speed = fan_get_speed(info->bus, i); 292 | if (fan_speed > 0) 293 | rc = fan_set_present(info->bus, i, 1); 294 | else 295 | rc = fan_set_present(info->bus, i, 0); 296 | 297 | if (rc < 0) { 298 | fprintf(stderr, 299 | "fanctl: Failed to set fan present status\n"); 300 | break; 301 | } 302 | } 303 | 304 | return rc; 305 | } 306 | /* 307 | * Router function for any FAN operations that come via dbus 308 | */ 309 | static int fan_function_router(sd_bus_message *msg, void *user_data, 310 | sd_bus_error *ret_error) 311 | { 312 | /* Generic error reporter. */ 313 | int rc = -1; 314 | fan_info_t *info = user_data; 315 | 316 | /* Get the Operation. */ 317 | const char *fan_function = sd_bus_message_get_member(msg); 318 | if (fan_function == NULL) { 319 | fprintf(stderr, "fanctl: Null FAN function specified\n"); 320 | return sd_bus_reply_method_return(msg, "i", rc); 321 | } 322 | 323 | /* Route the user action to appropriate handlers. */ 324 | if ((strcmp(fan_function, "setMax") == 0)) { 325 | rc = fan_set_max_speed(info); 326 | return sd_bus_reply_method_return(msg, "i", rc); 327 | } 328 | if ((strcmp(fan_function, "updatePresent") == 0)) { 329 | rc = fan_update_present(info); 330 | return sd_bus_reply_method_return(msg, "i", rc); 331 | } 332 | 333 | return sd_bus_reply_method_return(msg, "i", rc); 334 | } 335 | 336 | /* Dbus Services offered by this FAN controller */ 337 | static const sd_bus_vtable fan_control_vtable[] = 338 | { 339 | SD_BUS_VTABLE_START(0), 340 | SD_BUS_METHOD("setMax", "", "i", &fan_function_router, 341 | SD_BUS_VTABLE_UNPRIVILEGED), 342 | SD_BUS_METHOD("updatePresent", "", "i", &fan_function_router, 343 | SD_BUS_VTABLE_UNPRIVILEGED), 344 | SD_BUS_VTABLE_END, 345 | }; 346 | 347 | int start_fan_services(fan_info_t *info) 348 | { 349 | /* Generic error reporter. */ 350 | int rc = -1; 351 | /* slot where we are offering the FAN dbus service. */ 352 | sd_bus_slot *fan_slot = NULL; 353 | const char *fan_object = "/org/openbmc/control/fans"; 354 | 355 | info->bus = NULL; 356 | /* Get a hook onto system bus. */ 357 | rc = sd_bus_open_system(&info->bus); 358 | if (rc < 0) { 359 | fprintf(stderr,"fanctl: Error opening system bus.\n"); 360 | return rc; 361 | } 362 | 363 | /* Install the object */ 364 | rc = sd_bus_add_object_vtable(info->bus, 365 | &fan_slot, 366 | fan_object, /* object path */ 367 | "org.openbmc.control.Fans", /* interface name */ 368 | fan_control_vtable, 369 | info); 370 | if (rc < 0) { 371 | fprintf(stderr, "fanctl: Failed to add object to dbus: %s\n", 372 | strerror(-rc)); 373 | return rc; 374 | } 375 | 376 | /* If we had success in adding the providers, request for a bus name. */ 377 | rc = sd_bus_request_name(info->bus, 378 | "org.openbmc.control.Fans", 0); 379 | if (rc < 0) { 380 | fprintf(stderr, "fanctl: Failed to acquire service name: %s\n", 381 | strerror(-rc)); 382 | return rc; 383 | } 384 | 385 | for (;;) { 386 | /* Process requests */ 387 | rc = sd_bus_process(info->bus, NULL); 388 | if (rc < 0) { 389 | fprintf(stderr, "fanctl: Failed to process bus: %s\n", 390 | strerror(-rc)); 391 | break; 392 | } 393 | if (rc > 0) { 394 | continue; 395 | } 396 | 397 | rc = sd_bus_wait(info->bus, (uint64_t) - 1); 398 | if (rc < 0) { 399 | fprintf(stderr, "fanctl: Failed to wait on bus: %s\n", 400 | strerror(-rc)); 401 | break; 402 | } 403 | } 404 | 405 | sd_bus_slot_unref(fan_slot); 406 | sd_bus_unref(info->bus); 407 | 408 | return rc; 409 | } 410 | 411 | static int str_to_int(char *str) 412 | { 413 | long val; 414 | char *temp; 415 | 416 | val = strtol(str, &temp, 10); 417 | if (temp == str || *temp != '\0' || 418 | ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE)) 419 | return -1; 420 | if (val < 0) 421 | return -1; 422 | 423 | return (int)val; 424 | } 425 | 426 | static int parse_argument(int argc, char **argv, fan_info_t *info) 427 | { 428 | int c; 429 | struct option long_options[] = 430 | { 431 | {"fan_num", required_argument, 0, 'f'}, 432 | {"core_num", required_argument, 0, 'c'}, 433 | {"cpu_num", required_argument, 0, 'p'}, 434 | {"dimm_num", required_argument, 0, 'd'}, 435 | {0, 0, 0, 0} 436 | }; 437 | 438 | while (1) { 439 | c = getopt_long (argc, argv, "c:d:f:p:", long_options, NULL); 440 | 441 | /* Detect the end of the options. */ 442 | if (c == -1) 443 | break; 444 | 445 | switch (c) { 446 | case 'f': 447 | info->fan_num = str_to_int(optarg); 448 | if (info->fan_num == -1) { 449 | fprintf(stderr, "fanctl: Wrong fan_num: %s\n", optarg); 450 | return -1; 451 | } 452 | break; 453 | case 'c': 454 | info->core_num = str_to_int(optarg); 455 | if (info->core_num == -1) { 456 | fprintf(stderr, "fanctl: Wrong core_num: %s\n", optarg); 457 | return -1; 458 | } 459 | break; 460 | case 'p': 461 | info->cpu_num = str_to_int(optarg); 462 | if (info->cpu_num == -1) { 463 | fprintf(stderr, "fanctl: Wrong cpu_num: %s\n", optarg); 464 | return -1; 465 | } 466 | break; 467 | case 'd': 468 | info->dimm_num = str_to_int(optarg); 469 | if (info->dimm_num == -1) { 470 | fprintf(stderr, "fanctl: Wrong dimm_num: %s\n", optarg); 471 | return -1; 472 | } 473 | break; 474 | default: 475 | fprintf(stderr, "fanctl: Wrong argument\n"); 476 | return -1; 477 | } 478 | } 479 | 480 | return 0; 481 | } 482 | 483 | int main(int argc, char **argv) 484 | { 485 | int rc = 0; 486 | fan_info_t fan_info; 487 | 488 | memset(&fan_info, 0, sizeof(fan_info)); 489 | rc = parse_argument(argc, argv, &fan_info); 490 | if (rc < 0) { 491 | fprintf(stderr, "fanctl: Error parse argument\n"); 492 | return rc; 493 | } 494 | /* This call is not supposed to return. If it does, then an error */ 495 | rc = start_fan_services(&fan_info); 496 | if (rc < 0) { 497 | fprintf(stderr, "fanctl: Error starting FAN Services. Exiting"); 498 | } 499 | 500 | return rc; 501 | } 502 | -------------------------------------------------------------------------------- /flashbios/Makefile: -------------------------------------------------------------------------------- 1 | BINS=flash_bios 2 | include ../gdbus.mk 3 | include ../rules.mk 4 | -------------------------------------------------------------------------------- /flashbios/flash_bios_obj.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* ------------------------------------------------------------------------- */ 10 | static const gchar* dbus_object_path = "/org/openbmc/control/flash"; 11 | static const gchar* dbus_name = "org.openbmc.control.Flash"; 12 | static const gchar* FLASHER_BIN = "flasher.exe"; 13 | 14 | static GDBusObjectManagerServer *manager = NULL; 15 | 16 | void 17 | catch_child(int sig_num) 18 | { 19 | /* when we get here, we know there's a zombie child waiting */ 20 | int child_status; 21 | 22 | wait(&child_status); 23 | printf("flasher exited.\n"); 24 | } 25 | 26 | int 27 | update(Flash* flash, const char* obj_path) 28 | { 29 | pid_t pid; 30 | int status=-1; 31 | pid = fork(); 32 | if(pid == 0) 33 | { 34 | const gchar* name = flash_get_flasher_name(flash); 35 | const gchar* inst = flash_get_flasher_instance(flash); 36 | const gchar* filename = flash_get_filename(flash); 37 | status = execlp(name, name, inst, filename, obj_path, NULL); 38 | return status; 39 | } 40 | return 0; 41 | } 42 | 43 | static gboolean 44 | on_init(Flash *f, 45 | GDBusMethodInvocation *invocation, 46 | gpointer user_data) 47 | { 48 | flash_complete_init(f,invocation); 49 | 50 | //tune flash 51 | if(strcmp(flash_get_flasher_instance(f),"bios") == 0) 52 | { 53 | flash_set_filename(f,""); 54 | const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data); 55 | int rc = update(f,obj_path); 56 | if(rc==-1) 57 | { 58 | printf("ERROR FlashControl: Unable to init\n"); 59 | } 60 | sleep(3); 61 | rc = update(f,obj_path); 62 | 63 | } 64 | return TRUE; 65 | } 66 | 67 | static gboolean 68 | on_lock(SharedResource *lock, 69 | GDBusMethodInvocation *invocation, 70 | gchar* name, 71 | gpointer user_data) 72 | { 73 | gboolean locked = shared_resource_get_lock(lock); 74 | if(locked) 75 | { 76 | const gchar* name = shared_resource_get_name(lock); 77 | printf("ERROR: BIOS Flash is already locked: %s\n",name); 78 | } 79 | else 80 | { 81 | printf("Locking BIOS Flash: %s\n",name); 82 | shared_resource_set_lock(lock,true); 83 | shared_resource_set_name(lock,name); 84 | } 85 | shared_resource_complete_lock(lock,invocation); 86 | return TRUE; 87 | } 88 | 89 | static gboolean 90 | on_is_locked(SharedResource *lock, 91 | GDBusMethodInvocation *invocation, 92 | gpointer user_data) 93 | { 94 | gboolean locked = shared_resource_get_lock(lock); 95 | const gchar* name = shared_resource_get_name(lock); 96 | shared_resource_complete_is_locked(lock,invocation,locked,name); 97 | return TRUE; 98 | } 99 | 100 | static gboolean 101 | on_unlock(SharedResource *lock, 102 | GDBusMethodInvocation *invocation, 103 | gpointer user_data) 104 | { 105 | printf("Unlocking BIOS Flash\n"); 106 | shared_resource_set_lock(lock,false); 107 | shared_resource_set_name(lock,""); 108 | shared_resource_complete_unlock(lock,invocation); 109 | return TRUE; 110 | } 111 | 112 | static gboolean 113 | on_update_via_tftp(Flash *flash, 114 | GDBusMethodInvocation *invocation, 115 | gchar* url, 116 | gchar* write_file, 117 | gpointer user_data) 118 | { 119 | SharedResource *lock = object_get_shared_resource((Object*)user_data); 120 | gboolean locked = shared_resource_get_lock(lock); 121 | flash_complete_update_via_tftp(flash,invocation); 122 | if(locked) 123 | { 124 | const gchar* name = shared_resource_get_name(lock); 125 | printf("BIOS Flash is locked: %s\n",name); 126 | } 127 | else 128 | { 129 | printf("Flashing BIOS from TFTP: %s,%s\n",url,write_file); 130 | flash_set_filename(flash,write_file); 131 | flash_emit_download(flash,url,write_file); 132 | flash_set_status(flash,"Downloading"); 133 | } 134 | return TRUE; 135 | } 136 | 137 | static gboolean 138 | on_error(Flash *flash, 139 | GDBusMethodInvocation *invocation, 140 | gchar* error_msg, 141 | gpointer user_data) 142 | { 143 | SharedResource *lock = object_get_shared_resource((Object*)user_data); 144 | shared_resource_get_lock(lock); 145 | flash_set_status(flash, error_msg); 146 | flash_complete_error(flash,invocation); 147 | printf("ERROR: %s. Clearing locks\n",error_msg); 148 | shared_resource_set_lock(lock,false); 149 | shared_resource_set_name(lock,""); 150 | 151 | return TRUE; 152 | } 153 | 154 | static gboolean 155 | on_done(Flash *flash, 156 | GDBusMethodInvocation *invocation, 157 | gpointer user_data) 158 | { 159 | int rc = 0; 160 | SharedResource *lock = object_get_shared_resource((Object*)user_data); 161 | shared_resource_get_lock(lock); 162 | flash_set_status(flash, "Flash Done"); 163 | flash_complete_done(flash,invocation); 164 | printf("Flash Done. Clearing locks\n"); 165 | shared_resource_set_lock(lock,false); 166 | shared_resource_set_name(lock,""); 167 | const gchar* filename = flash_get_filename(flash); 168 | rc = unlink(filename); 169 | if(rc != 0 ) 170 | { 171 | printf("ERROR: Unable to delete file %s (%d)\n",filename,rc); 172 | } 173 | 174 | return TRUE; 175 | } 176 | 177 | static gboolean 178 | on_update(Flash *flash, 179 | GDBusMethodInvocation *invocation, 180 | gchar* write_file, 181 | gpointer user_data) 182 | { 183 | int rc = 0; 184 | SharedResource *lock = object_get_shared_resource((Object*)user_data); 185 | gboolean locked = shared_resource_get_lock(lock); 186 | flash_set_status(flash,"Flashing"); 187 | flash_complete_update(flash,invocation); 188 | if(locked) 189 | { 190 | const gchar* name = shared_resource_get_name(lock); 191 | printf("BIOS Flash is locked: %s\n",name); 192 | } 193 | else 194 | { 195 | printf("Flashing BIOS from: %s\n",write_file); 196 | flash_set_status(flash, "Flashing"); 197 | shared_resource_set_lock(lock,true); 198 | shared_resource_set_name(lock,dbus_object_path); 199 | flash_set_filename(flash,write_file); 200 | const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data); 201 | rc = update(flash,obj_path); 202 | if(!rc) 203 | { 204 | shared_resource_set_lock(lock,false); 205 | shared_resource_set_name(lock,""); 206 | } 207 | } 208 | return TRUE; 209 | } 210 | 211 | static void 212 | on_flash_progress(GDBusConnection* connection, 213 | const gchar* sender_name, 214 | const gchar* object_path, 215 | const gchar* interface_name, 216 | const gchar* signal_name, 217 | GVariant* parameters, 218 | gpointer user_data) 219 | { 220 | Flash *flash = object_get_flash((Object*)user_data); 221 | object_get_shared_resource((Object*)user_data); 222 | GVariantIter *iter = g_variant_iter_new(parameters); 223 | g_variant_iter_next_value(iter); 224 | GVariant* v_progress = g_variant_iter_next_value(iter); 225 | 226 | uint8_t progress = g_variant_get_byte(v_progress); 227 | 228 | gchar *s; 229 | s = g_strdup_printf("Flashing: %d%%",progress); 230 | flash_set_status(flash,s); 231 | g_free(s); 232 | } 233 | 234 | static void 235 | on_bus_acquired(GDBusConnection *connection, 236 | const gchar *name, 237 | gpointer user_data) 238 | { 239 | ObjectSkeleton *object; 240 | cmdline *cmd = user_data; 241 | manager = g_dbus_object_manager_server_new(dbus_object_path); 242 | int i=0; 243 | 244 | gchar *flasher_file = g_strdup_printf("%s", FLASHER_BIN); 245 | 246 | const char* inst[] = {"bios"}; 247 | for(i=0;i<1;i++) 248 | { 249 | gchar* s; 250 | s = g_strdup_printf("%s/%s",dbus_object_path,inst[i]); 251 | object = object_skeleton_new(s); 252 | g_free(s); 253 | 254 | Flash* flash = flash_skeleton_new(); 255 | object_skeleton_set_flash(object, flash); 256 | g_object_unref(flash); 257 | 258 | SharedResource* lock = shared_resource_skeleton_new(); 259 | object_skeleton_set_shared_resource(object, lock); 260 | g_object_unref(lock); 261 | 262 | shared_resource_set_lock(lock,false); 263 | shared_resource_set_name(lock,""); 264 | 265 | flash_set_flasher_name(flash,FLASHER_BIN); 266 | flash_set_flasher_instance(flash,inst[i]); 267 | //g_free (s); 268 | 269 | 270 | //define method callbacks here 271 | g_signal_connect(lock, 272 | "handle-lock", 273 | G_CALLBACK(on_lock), 274 | NULL); /* user_data */ 275 | g_signal_connect(lock, 276 | "handle-unlock", 277 | G_CALLBACK(on_unlock), 278 | NULL); /* user_data */ 279 | g_signal_connect(lock, 280 | "handle-is-locked", 281 | G_CALLBACK(on_is_locked), 282 | NULL); /* user_data */ 283 | 284 | g_signal_connect(flash, 285 | "handle-update", 286 | G_CALLBACK(on_update), 287 | object); /* user_data */ 288 | 289 | g_signal_connect(flash, 290 | "handle-error", 291 | G_CALLBACK(on_error), 292 | object); /* user_data */ 293 | 294 | g_signal_connect(flash, 295 | "handle-done", 296 | G_CALLBACK(on_done), 297 | object); /* user_data */ 298 | 299 | g_signal_connect(flash, 300 | "handle-update-via-tftp", 301 | G_CALLBACK(on_update_via_tftp), 302 | object); /* user_data */ 303 | 304 | g_signal_connect(flash, 305 | "handle-init", 306 | G_CALLBACK(on_init), 307 | object); /* user_data */ 308 | 309 | s = g_strdup_printf("/org/openbmc/control/%s",inst[i]); 310 | g_dbus_connection_signal_subscribe(connection, 311 | NULL, 312 | "org.openbmc.FlashControl", 313 | "Progress", 314 | s, 315 | NULL, 316 | G_DBUS_SIGNAL_FLAGS_NONE, 317 | (GDBusSignalCallback) on_flash_progress, 318 | object, 319 | NULL ); 320 | 321 | g_free(s); 322 | 323 | 324 | flash_set_filename(flash,""); 325 | /* Export the object (@manager takes its own reference to @object) */ 326 | g_dbus_object_manager_server_set_connection(manager, connection); 327 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 328 | g_object_unref(object); 329 | } 330 | g_free(flasher_file); 331 | } 332 | 333 | static void 334 | on_name_acquired(GDBusConnection *connection, 335 | const gchar *name, 336 | gpointer user_data) 337 | { 338 | // g_print ("Acquired the name %s\n", name); 339 | } 340 | 341 | static void 342 | on_name_lost(GDBusConnection *connection, 343 | const gchar *name, 344 | gpointer user_data) 345 | { 346 | //g_print ("Lost the name %s\n", name); 347 | } 348 | 349 | gint 350 | main(gint argc, gchar *argv[]) 351 | { 352 | GMainLoop *loop; 353 | cmdline cmd; 354 | cmd.argc = argc; 355 | cmd.argv = argv; 356 | guint id; 357 | loop = g_main_loop_new(NULL, FALSE); 358 | 359 | signal(SIGCHLD, catch_child); 360 | id = g_bus_own_name(DBUS_TYPE, 361 | dbus_name, 362 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 363 | G_BUS_NAME_OWNER_FLAGS_REPLACE, 364 | on_bus_acquired, 365 | on_name_acquired, 366 | on_name_lost, 367 | &cmd, 368 | NULL); 369 | 370 | g_main_loop_run(loop); 371 | 372 | g_bus_unown_name(id); 373 | g_main_loop_unref(loop); 374 | return 0; 375 | } 376 | -------------------------------------------------------------------------------- /gdbus.mk: -------------------------------------------------------------------------------- 1 | PACKAGE_DEPS=gio-unix-2.0 glib-2.0 2 | LDLIBS+=-lopenbmc_intf 3 | 4 | %.o: %_obj.c 5 | $(CC) -c $(ALL_CFLAGS) -o $@ $< 6 | -------------------------------------------------------------------------------- /ledctl/Makefile: -------------------------------------------------------------------------------- 1 | BINS=led_controller 2 | include ../sdbus.mk 3 | include ../rules.mk 4 | -------------------------------------------------------------------------------- /ledctl/led_controller.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static int led_stable_state_function(const char *, const char *); 9 | static int led_default_blink(const char *, const char *); 10 | static int read_led(const char *, const char *, void *, const size_t); 11 | static int led_custom_blink(const char *, sd_bus_message *); 12 | 13 | /* 14 | * These are control files that are present for each led under 15 | *'/sys/class/leds//' which are used to trigger action 16 | * on the respective leds by writing predefined data. 17 | */ 18 | const char *power_ctrl = "brightness"; 19 | const char *blink_ctrl = "trigger"; 20 | const char *duty_on = "delay_on"; 21 | const char *duty_off = "delay_off"; 22 | 23 | /* 24 | * -------------------------------------------------- 25 | * Given the dbus path, returns the name of the LED 26 | * -------------------------------------------------- 27 | */ 28 | char * 29 | get_led_name(const char *dbus_path) 30 | { 31 | char *led_name = NULL; 32 | 33 | /* Get the led name from /org/openbmc/control/led/ */ 34 | led_name = strrchr(dbus_path, '/'); 35 | if(led_name) 36 | { 37 | led_name++; 38 | } 39 | 40 | return led_name; 41 | } 42 | 43 | /* 44 | * ------------------------------------------------------------------------- 45 | * Writes the 'on / off / blink' trigger to leds. 46 | * ------------------------------------------------------------------------- 47 | */ 48 | int 49 | write_to_led(const char *name, const char *ctrl_file, const char *value) 50 | { 51 | /* Generic error reporter. */ 52 | int rc = -1; 53 | 54 | /* To get /sys/class/leds// */ 55 | char led_path[128] = {0}; 56 | 57 | int len = 0; 58 | len = snprintf(led_path, sizeof(led_path), 59 | "/sys/class/leds/%s/%s",name, ctrl_file); 60 | if(len >= sizeof(led_path)) 61 | { 62 | fprintf(stderr, "Error. LED path is too long. :[%d]\n",len); 63 | return rc; 64 | } 65 | 66 | FILE *fp = fopen(led_path,"w"); 67 | if(fp == NULL) 68 | { 69 | fprintf(stderr,"Error:[%s] opening:[%s]\n",strerror(errno),led_path); 70 | return rc; 71 | } 72 | 73 | rc = fwrite(value, strlen(value), 1, fp); 74 | if(rc != 1) 75 | { 76 | fprintf(stderr, "Error:[%s] writing to :[%s]\n",strerror(errno),led_path); 77 | } 78 | 79 | fclose(fp); 80 | 81 | /* When we get here, rc would be what it was from writing to the file */ 82 | return (rc == 1) ? 0 : -1; 83 | } 84 | 85 | /* 86 | * ---------------------------------------------------------------- 87 | * Router function for any LED operations that come via dbus 88 | *---------------------------------------------------------------- 89 | */ 90 | static int 91 | led_function_router(sd_bus_message *msg, void *user_data, 92 | sd_bus_error *ret_error) 93 | { 94 | /* Generic error reporter. */ 95 | int rc = -1; 96 | 97 | /* Extract the led name from the full dbus path */ 98 | const char *led_path = sd_bus_message_get_path(msg); 99 | if(led_path == NULL) 100 | { 101 | fprintf(stderr, "Error. LED path is empty"); 102 | return sd_bus_reply_method_return(msg, "i", rc); 103 | } 104 | 105 | char *led_name = get_led_name(led_path); 106 | if(led_name == NULL) 107 | { 108 | fprintf(stderr, "Invalid LED name for path :[%s]\n",led_path); 109 | return sd_bus_reply_method_return(msg, "i", rc); 110 | } 111 | 112 | /* Now that we have the LED name, get the Operation. */ 113 | const char *led_function = sd_bus_message_get_member(msg); 114 | if(led_function == NULL) 115 | { 116 | fprintf(stderr, "Null LED function specified for : [%s]\n",led_name); 117 | return sd_bus_reply_method_return(msg, "i", rc); 118 | } 119 | 120 | /* Route the user action to appropriate handlers. */ 121 | if( (strcmp(led_function, "setOn") == 0) || 122 | (strcmp(led_function, "setOff") == 0)) 123 | { 124 | rc = led_stable_state_function(led_name, led_function); 125 | return sd_bus_reply_method_return(msg, "i", rc); 126 | } 127 | else if( (strcmp(led_function, "setBlinkFast") == 0) || 128 | (strcmp(led_function, "setBlinkSlow") == 0)) 129 | { 130 | rc = led_default_blink(led_name, led_function); 131 | return sd_bus_reply_method_return(msg, "i", rc); 132 | } 133 | else if(strcmp(led_function, "BlinkCustom") == 0) 134 | { 135 | rc = led_custom_blink(led_name, msg); 136 | return sd_bus_reply_method_return(msg, "i", rc); 137 | } 138 | else if(strcmp(led_function, "GetLedState") == 0) 139 | { 140 | char value_str[10] = {0}; 141 | const char *led_state = NULL; 142 | 143 | rc = read_led(led_name, power_ctrl, value_str, sizeof(value_str)-1); 144 | if(rc >= 0) 145 | { 146 | /* LED is active HI */ 147 | led_state = strtoul(value_str, NULL, 0) ? "On" : "Off"; 148 | } 149 | return sd_bus_reply_method_return(msg, "is", rc, led_state); 150 | } 151 | else 152 | { 153 | fprintf(stderr,"Invalid LED function:[%s]\n",led_function); 154 | } 155 | 156 | return sd_bus_reply_method_return(msg, "i", rc); 157 | } 158 | 159 | /* 160 | * -------------------------------------------------------------- 161 | * Turn On or Turn Off the LED 162 | * -------------------------------------------------------------- 163 | */ 164 | static int 165 | led_stable_state_function(const char *led_name, const char *led_function) 166 | { 167 | /* Generic error reporter. */ 168 | int rc = -1; 169 | 170 | const char *value = NULL; 171 | if(strcmp(led_function, "setOff") == 0) 172 | { 173 | /* LED active low */ 174 | value = "0"; 175 | } 176 | else if(strcmp(led_function, "setOn") == 0) 177 | { 178 | value = "255"; 179 | } 180 | else 181 | { 182 | fprintf(stderr,"Invalid LED stable state operation:[%s] \n",led_function); 183 | return rc; 184 | } 185 | 186 | /* 187 | * Before doing anything, need to turn off the blinking 188 | * if there is one in progress by writing 'none' to trigger 189 | */ 190 | rc = write_to_led(led_name, blink_ctrl, "none"); 191 | if(rc < 0) 192 | { 193 | fprintf(stderr,"Error disabling blink. Function:[%s]\n", led_function); 194 | return rc; 195 | } 196 | 197 | /* 198 | * Open the brightness file and write corresponding values. 199 | */ 200 | rc = write_to_led(led_name, power_ctrl, value); 201 | if(rc < 0) 202 | { 203 | fprintf(stderr,"Error driving LED. Function:[%s]\n", led_function); 204 | } 205 | 206 | return rc; 207 | } 208 | 209 | //----------------------------------------------------------------------------------- 210 | // Given the on and off duration, applies the action on the specified LED. 211 | //----------------------------------------------------------------------------------- 212 | int 213 | blink_led(const char *led_name, const char *on_duration, const char *off_duration) 214 | { 215 | /* Generic error reporter */ 216 | int rc = -1; 217 | 218 | /* Protocol demands that 'timer' be echoed to 'trigger' */ 219 | rc = write_to_led(led_name, blink_ctrl, "timer"); 220 | if(rc < 0) 221 | { 222 | fprintf(stderr,"Error writing timer to Led:[%s]\n", led_name); 223 | return rc; 224 | } 225 | 226 | /* 227 | * After writing 'timer to 'trigger', 2 new files get generated namely 228 | *'delay_on' and 'delay_off' which are telling the time duration for a 229 | * particular LED on and off. 230 | */ 231 | rc = write_to_led(led_name, duty_on, on_duration); 232 | if(rc < 0) 233 | { 234 | fprintf(stderr,"Error writing [%s] to delay_on:[%s]\n",on_duration,led_name); 235 | return rc; 236 | } 237 | 238 | rc = write_to_led(led_name, duty_off, off_duration); 239 | if(rc < 0) 240 | { 241 | fprintf(stderr,"Error writing [%s] to delay_off:[%s]\n",off_duration,led_name); 242 | } 243 | 244 | return rc; 245 | } 246 | 247 | /* 248 | * ---------------------------------------------------- 249 | * Default blink action on the LED. 250 | * ---------------------------------------------------- 251 | */ 252 | static int 253 | led_default_blink(const char *led_name, const char *blink_type) 254 | { 255 | /* Generic error reporter */ 256 | int rc = -1; 257 | 258 | /* How long the LED needs to be in on and off state while blinking */ 259 | const char *on_duration = NULL; 260 | const char *off_duration = NULL; 261 | if(strcmp(blink_type, "setBlinkSlow") == 0) 262 | { 263 | //*Delay 900 millisec before 'on' and delay 900 millisec before off */ 264 | on_duration = "900"; 265 | off_duration = "900"; 266 | } 267 | else if(strcmp(blink_type, "setBlinkFast") == 0) 268 | { 269 | /* Delay 200 millisec before 'on' and delay 200 millisec before off */ 270 | on_duration = "200"; 271 | off_duration = "200"; 272 | } 273 | else 274 | { 275 | fprintf(stderr,"Invalid blink operation:[%s]\n",blink_type); 276 | return rc; 277 | } 278 | 279 | rc = blink_led(led_name, on_duration, off_duration); 280 | 281 | return rc; 282 | } 283 | 284 | /* 285 | * ------------------------------------------------- 286 | * Blinks at user defined 'on' and 'off' intervals. 287 | * ------------------------------------------------- 288 | */ 289 | static int 290 | led_custom_blink(const char *led_name, sd_bus_message *msg) 291 | { 292 | /* Generic error reporter. */ 293 | int rc = -1; 294 | int led_len = 0; 295 | 296 | /* User supplied 'on' and 'off' duration converted into string */ 297 | char on_duration[32] = {0}; 298 | char off_duration[32] = {0}; 299 | 300 | /* User supplied 'on' and 'off' duration */ 301 | uint32_t user_input_on = 0; 302 | uint32_t user_input_off = 0; 303 | 304 | /* Extract values into 'ss' ( string, string) */ 305 | rc = sd_bus_message_read(msg, "uu", &user_input_on, &user_input_off); 306 | if(rc < 0) 307 | { 308 | fprintf(stderr, "Failed to read 'on' and 'off' duration.[%s]\n", strerror(-rc)); 309 | } 310 | else 311 | { 312 | /* 313 | * Converting user supplied integer arguments into string as required by 314 | * sys interface. The top level REST will make sure that an error is 315 | * thrown right away on invalid inputs. However, REST is allowing the 316 | * unsigned decimal and floating numbers but when its received here, its 317 | * received as decimal so no input validation needed. 318 | */ 319 | led_len = snprintf(on_duration, sizeof(on_duration), 320 | "%d",user_input_on); 321 | if(led_len >= sizeof(on_duration)) 322 | { 323 | fprintf(stderr, "Error. Blink ON duration is too long. :[%d]\n",led_len); 324 | return rc; 325 | } 326 | 327 | led_len = snprintf(off_duration, sizeof(off_duration), 328 | "%d",user_input_off); 329 | if(led_len >= sizeof(off_duration)) 330 | { 331 | fprintf(stderr, "Error. Blink OFF duration is too long. :[%d]\n",led_len); 332 | return rc; 333 | } 334 | 335 | /* We are good here.*/ 336 | rc = blink_led(led_name, on_duration, off_duration); 337 | } 338 | return rc; 339 | } 340 | 341 | /* 342 | * --------------------------------------------------------------- 343 | * Gets the current value of passed in LED file 344 | * Mainly used for reading 'brightness' 345 | * NOTE : It is the responsibility of the caller to allocate 346 | * sufficient space for buffer. This will read up to user supplied 347 | * size -or- entire contents of file whichever is smaller 348 | * ---------------------------------------------------------------- 349 | */ 350 | static int 351 | read_led(const char *name, const char *ctrl_file, 352 | void *value, const size_t len) 353 | { 354 | /* Generic error reporter. */ 355 | int rc = -1; 356 | int count = 0; 357 | 358 | if(value == NULL || len <= 0) 359 | { 360 | fprintf(stderr, "Invalid buffer passed to LED read\n"); 361 | return rc; 362 | } 363 | 364 | /* To get /sys/class/leds// */ 365 | char led_path[128] = {0}; 366 | 367 | int led_len = 0; 368 | led_len = snprintf(led_path, sizeof(led_path), 369 | "/sys/class/leds/%s/%s",name, ctrl_file); 370 | if(led_len >= sizeof(led_path)) 371 | { 372 | fprintf(stderr, "Error. LED path is too long. :[%d]\n",led_len); 373 | return rc; 374 | } 375 | 376 | FILE *fp = fopen(led_path,"rb"); 377 | if(fp == NULL) 378 | { 379 | fprintf(stderr,"Error:[%s] opening:[%s]\n",strerror(errno),led_path); 380 | return rc; 381 | } 382 | 383 | char *sysfs_value = (char *)value; 384 | while(!feof(fp) && (count < len)) 385 | { 386 | sysfs_value[count++] = fgetc(fp); 387 | } 388 | 389 | fclose(fp); 390 | return 0; 391 | } 392 | 393 | /* 394 | * ----------------------------------------------- 395 | * Dbus Services offered by this LED controller 396 | * ----------------------------------------------- 397 | */ 398 | static const sd_bus_vtable led_control_vtable[] = 399 | { 400 | SD_BUS_VTABLE_START(0), 401 | SD_BUS_METHOD("setOn", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 402 | SD_BUS_METHOD("setOff", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 403 | SD_BUS_METHOD("setBlinkFast", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 404 | SD_BUS_METHOD("setBlinkSlow", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 405 | SD_BUS_METHOD("GetLedState", "", "is", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 406 | SD_BUS_METHOD("BlinkCustom", "uu", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED), 407 | SD_BUS_VTABLE_END, 408 | }; 409 | 410 | /* 411 | * --------------------------------------------- 412 | * Interested in all files except standard ones 413 | * --------------------------------------------- 414 | */ 415 | int 416 | led_select(const struct dirent *entry) 417 | { 418 | if( (strcmp(entry->d_name, ".") == 0) || 419 | (strcmp(entry->d_name, "..") == 0)) 420 | { 421 | return 0; 422 | } 423 | return 1; 424 | } 425 | 426 | /* 427 | * ------------------------------------------------ 428 | * Called as part of setting up skeleton services. 429 | * ----------------------------------------------- 430 | */ 431 | int 432 | start_led_services() 433 | { 434 | static const char *led_dbus_root = "/org/openbmc/control/led"; 435 | 436 | /* Generic error reporter. */ 437 | int rc = -1; 438 | int num_leds = 0; 439 | int count_leds = 0; 440 | 441 | /* Bus and slot where we are offering the LED dbus service. */ 442 | sd_bus *bus_type = NULL; 443 | sd_bus_slot *led_slot = NULL; 444 | 445 | /* For walking '/sys/class/leds/' looking for names of LED.*/ 446 | struct dirent **led_list; 447 | 448 | /* Get a hook onto system bus. */ 449 | rc = sd_bus_open_system(&bus_type); 450 | if(rc < 0) 451 | { 452 | fprintf(stderr,"Error opening system bus.\n"); 453 | return rc; 454 | } 455 | 456 | count_leds = num_leds = scandir("/sys/class/leds/", 457 | &led_list, led_select, alphasort); 458 | if(num_leds <= 0) 459 | { 460 | fprintf(stderr,"No LEDs present in the system\n"); 461 | 462 | sd_bus_slot_unref(led_slot); 463 | sd_bus_unref(bus_type); 464 | return rc; 465 | } 466 | 467 | /* Install a freedesktop object manager */ 468 | rc = sd_bus_add_object_manager(bus_type, NULL, led_dbus_root); 469 | if(rc < 0) { 470 | fprintf(stderr, "Failed to add object to dbus: %s\n", 471 | strerror(-rc)); 472 | 473 | sd_bus_slot_unref(led_slot); 474 | sd_bus_unref(bus_type); 475 | return rc; 476 | } 477 | 478 | /* Fully qualified Dbus object for a particular LED */ 479 | char led_object[128] = {0}; 480 | int len = 0; 481 | 482 | /* For each led present, announce the service on dbus. */ 483 | while(num_leds--) 484 | { 485 | memset(led_object, 0x0, sizeof(led_object)); 486 | 487 | len = snprintf(led_object, sizeof(led_object), "%s%s%s", 488 | led_dbus_root, "/", led_list[num_leds]->d_name); 489 | 490 | if(len >= sizeof(led_object)) 491 | { 492 | fprintf(stderr, "Error. LED object is too long:[%d]\n",len); 493 | rc = -1; 494 | break; 495 | } 496 | 497 | /* Install the object */ 498 | rc = sd_bus_add_object_vtable(bus_type, 499 | &led_slot, 500 | led_object, /* object path */ 501 | "org.openbmc.Led", /* interface name */ 502 | led_control_vtable, 503 | NULL); 504 | 505 | if(rc < 0) 506 | { 507 | fprintf(stderr, "Failed to add object to dbus: %s\n", strerror(-rc)); 508 | break; 509 | } 510 | 511 | rc = sd_bus_emit_object_added(bus_type, led_object); 512 | 513 | if(rc < 0) 514 | { 515 | fprintf(stderr, "Failed to emit InterfacesAdded " 516 | "signal: %s\n", strerror(-rc)); 517 | break; 518 | } 519 | } 520 | 521 | /* Done with all registration. */ 522 | while(count_leds > 0) 523 | { 524 | free(led_list[--count_leds]); 525 | } 526 | free(led_list); 527 | 528 | /* If we had success in adding the providers, request for a bus name. */ 529 | if(rc >= 0) 530 | { 531 | /* Take one in OpenBmc */ 532 | rc = sd_bus_request_name(bus_type, "org.openbmc.control.led", 0); 533 | if(rc < 0) 534 | { 535 | fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-rc)); 536 | } 537 | else 538 | { 539 | for(;;) 540 | { 541 | /* Process requests */ 542 | rc = sd_bus_process(bus_type, NULL); 543 | if(rc < 0) 544 | { 545 | fprintf(stderr, "Failed to process bus: %s\n", strerror(-rc)); 546 | break; 547 | } 548 | if(rc > 0) 549 | { 550 | continue; 551 | } 552 | 553 | rc = sd_bus_wait(bus_type, (uint64_t) - 1); 554 | if(rc < 0) 555 | { 556 | fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-rc)); 557 | break; 558 | } 559 | } 560 | } 561 | } 562 | sd_bus_slot_unref(led_slot); 563 | sd_bus_unref(bus_type); 564 | 565 | return rc; 566 | } 567 | 568 | int 569 | main(void) 570 | { 571 | int rc = 0; 572 | 573 | /* This call is not supposed to return. If it does, then an error */ 574 | rc = start_led_services(); 575 | if(rc < 0) 576 | { 577 | fprintf(stderr, "Error starting LED Services. Exiting"); 578 | } 579 | 580 | return rc; 581 | } 582 | -------------------------------------------------------------------------------- /libopenbmc_intf/GPIOS.md: -------------------------------------------------------------------------------- 1 | # GPIO JSON format 2 | 3 | GPIO definitions are stored in '/etc/default/obmc/gpio/gpio_defs.json' on the 4 | BMC. That file has 2 sections - 'gpio_configs' and 'gpio_definitions'. 5 | 6 | ## gpio_configs 7 | 8 | This section contains the GPIOs used in power control. 9 | 10 | It looks like: 11 | 12 | ```json 13 | { 14 | "gpio_configs": { 15 | "power_config": { 16 | 17 | #See code in op-pwrctl for details 18 | 19 | #Required 20 | "power_good_in": "...", 21 | 22 | #Required 23 | "power_up_outs": [ 24 | {"name": "...", "polarity": true/false}, 25 | {"name": "...", "polarity": true/false} 26 | ], 27 | 28 | #Optional 29 | "reset_outs": [ 30 | {"name": "...", "polarity": true/false} 31 | ], 32 | 33 | #Optional 34 | "latch_out": "...", 35 | 36 | #Optional 37 | "pci_reset_outs": [ 38 | {"name": "...", "polarity": true/false, "hold": true/false} 39 | ] 40 | } 41 | } 42 | } 43 | ``` 44 | 45 | ## gpio_definitions 46 | 47 | This section contains The GPIO pins and directions. 48 | 49 | It looks like: 50 | 51 | ```json 52 | { 53 | "gpio_definitions": [ 54 | { 55 | 56 | #The name to look up this entry. 57 | "name": "SOFTWARE_PGOOD", 58 | 59 | #The GPIO pin. 60 | "pin": "R1", 61 | 62 | #Alternatively to the pin, can use 'num' which is the 63 | #raw number the GPIO would be accessed with. 64 | "num": 7, 65 | 66 | #The GPIO direction - in, out, rising, falling, or both 67 | "direction": "out" 68 | }, 69 | { 70 | ... 71 | } 72 | ] 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /libopenbmc_intf/Makefile: -------------------------------------------------------------------------------- 1 | libdir=/usr/lib 2 | includedir=/usr/include 3 | 4 | PACKAGE_DEPS=gio-unix-2.0 glib-2.0 5 | SONAME=libopenbmc_intf.so 6 | VERSION=1 7 | LIBOBMC=$(SONAME).$(VERSION) 8 | INCLUDES=openbmc_intf.h openbmc.h gpio.h gpio_configs.h 9 | 10 | LDLIBS+=$(shell pkg-config --libs $(PACKAGE_DEPS)) -lcjson 11 | ALL_CFLAGS+=$(shell pkg-config --cflags $(PACKAGE_DEPS)) -fPIC -Werror $(CFLAGS) 12 | 13 | all: $(SONAME) 14 | 15 | %.o: %.c 16 | $(CC) -c $(ALL_CFLAGS) -o $@ $< 17 | 18 | $(SONAME): $(LIBOBMC) 19 | ln -sf $^ $@ 20 | 21 | $(LIBOBMC): lib%.so.$(VERSION): %.o gpio.o gpio_configs.o gpio_json.o 22 | $(CC) -shared $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(SONAME) \ 23 | -o $@ $^ $(LDLIBS) 24 | 25 | install: $(SONAME) $(LIBOBMC) 26 | @mkdir -p $(DESTDIR)$(includedir) 27 | install $(INCLUDES) $(DESTDIR)$(includedir) 28 | @mkdir -p $(DESTDIR)$(libdir) 29 | install $(LIBOBMC) $(DESTDIR)$(libdir) 30 | ln -sf $(LIBOBMC) $(DESTDIR)$(libdir)/$(SONAME) 31 | 32 | clean: 33 | rm -f *.o $(LIBOBMC) $(SONAME) 34 | -------------------------------------------------------------------------------- /libopenbmc_intf/codegen: -------------------------------------------------------------------------------- 1 | gdbus-codegen --interface-prefix org.openbmc --c-generate-object-manager --generate-c-code $1 $1.xml 2 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "openbmc_intf.h" 14 | #include "gpio.h" 15 | #include "gpio_json.h" 16 | 17 | #include 18 | #include 19 | 20 | #define GPIO_PORT_OFFSET 8 21 | #define GPIO_BASE_PATH "/sys/class/gpio" 22 | #define DEV_NAME "/dev/gpiochip0" 23 | 24 | cJSON* gpio_json = NULL; 25 | 26 | int gpio_write(GPIO* gpio, uint8_t value) 27 | { 28 | g_assert (gpio != NULL); 29 | struct gpiohandle_data data; 30 | memset(&data, 0, sizeof(data)); 31 | data.values[0] = value; 32 | 33 | if (gpio->fd <= 0) 34 | { 35 | return GPIO_ERROR; 36 | } 37 | 38 | if (ioctl(gpio->fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data) < 0) 39 | { 40 | return GPIO_WRITE_ERROR; 41 | } 42 | 43 | return GPIO_OK; 44 | } 45 | 46 | int gpio_read(GPIO* gpio, uint8_t *value) 47 | { 48 | g_assert (gpio != NULL); 49 | struct gpiohandle_data data; 50 | memset(&data, 0, sizeof(data)); 51 | 52 | if (gpio->fd <= 0) 53 | { 54 | return GPIO_ERROR; 55 | } 56 | 57 | if (ioctl(gpio->fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data) < 0) 58 | { 59 | return GPIO_READ_ERROR; 60 | } 61 | 62 | *value = data.values[0]; 63 | 64 | return GPIO_OK; 65 | } 66 | 67 | /** 68 | * Determine the GPIO base number for the system. It is found in 69 | * the 'base' file in the /sys/class/gpio/gpiochipX/ directory where the 70 | * /sys/class/gpio/gpiochipX/label file has a '1e780000.gpio' in it. 71 | * 72 | * Note: This method is ASPEED specific. Could add support for 73 | * additional SOCs in the future. 74 | * 75 | * @return int - the GPIO base number, or < 0 if not found 76 | */ 77 | int get_gpio_base() 78 | { 79 | int gpio_base = -1; 80 | 81 | DIR* dir = opendir(GPIO_BASE_PATH); 82 | if (dir == NULL) 83 | { 84 | fprintf(stderr, "Unable to open directory %s\n", 85 | GPIO_BASE_PATH); 86 | return -1; 87 | } 88 | 89 | struct dirent* entry; 90 | while ((entry = readdir(dir)) != NULL) 91 | { 92 | 93 | /* Look in the gpiochip directories for a file called 'label' */ 94 | /* that contains '1e780000.gpio', then in that directory read */ 95 | /* the GPIO base out of the 'base' file. */ 96 | 97 | if (strncmp(entry->d_name, "gpiochip", 8) != 0) 98 | { 99 | continue; 100 | } 101 | 102 | gboolean is_bmc = FALSE; 103 | char* label_name; 104 | int rc = asprintf(&label_name, "%s/%s/label", 105 | GPIO_BASE_PATH, entry->d_name); 106 | 107 | if (!rc) 108 | { 109 | continue; 110 | } 111 | 112 | FILE* fd = fopen(label_name, "r"); 113 | free(label_name); 114 | 115 | if (!fd) 116 | { 117 | continue; 118 | } 119 | 120 | char label[14]; 121 | if (fgets(label, 14, fd) != NULL) 122 | { 123 | if (strcmp(label, "1e780000.gpio") == 0) 124 | { 125 | is_bmc = TRUE; 126 | } 127 | } 128 | fclose(fd); 129 | 130 | if (!is_bmc) 131 | { 132 | continue; 133 | } 134 | 135 | char* base_name; 136 | rc = asprintf(&base_name, "%s/%s/base", 137 | GPIO_BASE_PATH, entry->d_name); 138 | 139 | if (!rc) 140 | { 141 | continue; 142 | } 143 | 144 | fd = fopen(base_name, "r"); 145 | free(base_name); 146 | 147 | if (!fd) 148 | { 149 | continue; 150 | } 151 | 152 | if (fscanf(fd, "%d", &gpio_base) != 1) 153 | { 154 | gpio_base = -1; 155 | } 156 | fclose(fd); 157 | 158 | /* We found the right file. No need to continue. */ 159 | break; 160 | } 161 | closedir(dir); 162 | 163 | if (gpio_base == -1) 164 | { 165 | fprintf(stderr, "Could not find GPIO base\n"); 166 | } 167 | 168 | return gpio_base; 169 | } 170 | 171 | /** 172 | * Converts the GPIO port/offset nomenclature value 173 | * to a number. Supports the ASPEED method where 174 | * num = base + (port * 8) + offset, and the port is an 175 | * A-Z character that converts to 0 to 25. The base 176 | * is obtained form the hardware. 177 | * 178 | * For example: "A5" -> 5, "Z7" -> 207 179 | * 180 | * @param[in] gpio - the GPIO name 181 | * 182 | * @return int - the GPIO number or < 0 if not found 183 | */ 184 | int convert_gpio_to_num(const char* gpio) 185 | { 186 | size_t len = strlen(gpio); 187 | if (len < 2) 188 | { 189 | fprintf(stderr, "Invalid GPIO name %s\n", gpio); 190 | return -1; 191 | } 192 | 193 | /* Read the offset from the last character */ 194 | if (!isdigit(gpio[len-1])) 195 | { 196 | fprintf(stderr, "Invalid GPIO offset in GPIO %s\n", gpio); 197 | return -1; 198 | } 199 | 200 | int offset = gpio[len-1] - '0'; 201 | 202 | /* Read the port from the second to last character */ 203 | if (!isalpha(gpio[len-2])) 204 | { 205 | fprintf(stderr, "Invalid GPIO port in GPIO %s\n", gpio); 206 | return -1; 207 | } 208 | int port = toupper(gpio[len-2]) - 'A'; 209 | 210 | /* Check for a 2 character port, like AA */ 211 | if ((len == 3) && isalpha(gpio[len-3])) 212 | { 213 | port += 26 * (toupper(gpio[len-3]) - 'A' + 1); 214 | } 215 | 216 | return (port * GPIO_PORT_OFFSET) + offset; 217 | } 218 | 219 | /** 220 | * Returns the cJSON pointer to the GPIO definition 221 | * for the GPIO passed in. 222 | * 223 | * @param[in] gpio_name - the GPIO name, like BMC_POWER_UP 224 | * 225 | * @return cJSON* - pointer to the cJSON object or NULL 226 | * if not found. 227 | */ 228 | cJSON* get_gpio_def(const char* gpio_name) 229 | { 230 | if (gpio_json == NULL) 231 | { 232 | gpio_json = load_json(); 233 | if (gpio_json == NULL) 234 | { 235 | return NULL; 236 | } 237 | } 238 | 239 | cJSON* gpio_defs = cJSON_GetObjectItem(gpio_json, "gpio_definitions"); 240 | g_assert(gpio_defs != NULL); 241 | 242 | cJSON* def; 243 | cJSON_ArrayForEach(def, gpio_defs) 244 | { 245 | cJSON* name = cJSON_GetObjectItem(def, "name"); 246 | g_assert(name != NULL); 247 | 248 | if (strcmp(name->valuestring, gpio_name) == 0) 249 | { 250 | return def; 251 | } 252 | } 253 | return NULL; 254 | } 255 | 256 | /** 257 | * Frees the gpio_json memory 258 | * 259 | * Can be called once when callers are done calling making calls 260 | * to gpio_init() so that the JSON only needs to be loaded once. 261 | */ 262 | void gpio_inits_done() 263 | { 264 | if (gpio_json != NULL) 265 | { 266 | cJSON_Delete(gpio_json); 267 | gpio_json = NULL; 268 | } 269 | } 270 | 271 | /** 272 | * Fills in the dev, direction, and num elements in 273 | * the GPIO structure. 274 | * 275 | * @param gpio - the GPIO structure to fill in 276 | * 277 | * @return GPIO_OK if successful 278 | */ 279 | int gpio_get_params(GPIO* gpio) 280 | { 281 | gpio->dev = g_strdup(GPIO_BASE_PATH); 282 | 283 | const cJSON* def = get_gpio_def(gpio->name); 284 | if (def == NULL) 285 | { 286 | fprintf(stderr, "Unable to find GPIO %s in the JSON\n", 287 | gpio->name); 288 | return GPIO_LOOKUP_ERROR; 289 | } 290 | 291 | const cJSON* dir = cJSON_GetObjectItem(def, "direction"); 292 | g_assert(dir != NULL); 293 | gpio->direction = g_strdup(dir->valuestring); 294 | 295 | /* Must use either 'num', like 87, or 'pin', like "A5" */ 296 | const cJSON* num = cJSON_GetObjectItem(def, "num"); 297 | if ((num != NULL) && cJSON_IsNumber(num)) 298 | { 299 | // When the "num" key is used, we will assume 300 | // that the system has gpiochip0 and that each 301 | // bank has the same amount of pins 302 | 303 | struct gpiochip_info info; 304 | int fd, ret; 305 | // Open the device 306 | fd = open(DEV_NAME, O_RDONLY); 307 | if (fd < 0) 308 | { 309 | fprintf(stderr, "Unable to open %s: %s\n", 310 | DEV_NAME, strerror(errno)); 311 | return GPIO_LOOKUP_ERROR; 312 | } 313 | 314 | // Query GPIO chip info 315 | ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &info); 316 | if (ret == -1) 317 | { 318 | fprintf(stderr, "Unable to get chip info from ioctl: %s\n", 319 | strerror(errno)); 320 | close(fd); 321 | return GPIO_LOOKUP_ERROR; 322 | } 323 | 324 | close(fd); 325 | printf("Number of pins per bank: %d\n", info.lines); 326 | 327 | gpio->num = (num->valueint) % info.lines; 328 | gpio->chip_id = (num->valueint) / info.lines; 329 | } 330 | else 331 | { 332 | const cJSON* pin = cJSON_GetObjectItem(def, "pin"); 333 | g_assert(pin != NULL); 334 | 335 | int pin_id = convert_gpio_to_num(pin->valuestring); 336 | if (pin_id < 0) 337 | { 338 | return GPIO_LOOKUP_ERROR; 339 | } 340 | gpio->num = (size_t) pin_id; 341 | } 342 | // TODO: For the purposes of skeleton and the projects that use it, 343 | // it should be safe to assume this will always be 0. Eventually skeleton 344 | // should be going away, but if the need arises before then this may need 345 | // to be updated to handle non-zero cases. 346 | gpio->chip_id = 0; 347 | return GPIO_OK; 348 | } 349 | 350 | int gpio_open(GPIO* gpio, uint8_t default_value) 351 | { 352 | g_assert (gpio != NULL); 353 | 354 | char buf[255]; 355 | sprintf(buf, "/dev/gpiochip%d", gpio->chip_id); 356 | gpio->fd = open(buf, 0); 357 | if (gpio->fd == -1) 358 | { 359 | return GPIO_OPEN_ERROR; 360 | } 361 | 362 | struct gpiohandle_request req; 363 | memset(&req, 0, sizeof(req)); 364 | strncpy(req.consumer_label, "skeleton-gpio", sizeof(req.consumer_label)); 365 | 366 | // open gpio for writing or reading 367 | if (gpio->direction == NULL) 368 | { 369 | gpio_close(gpio); 370 | return GPIO_OPEN_ERROR; 371 | } 372 | req.flags = (strcmp(gpio->direction,"in") == 0) ? GPIOHANDLE_REQUEST_INPUT 373 | : GPIOHANDLE_REQUEST_OUTPUT; 374 | 375 | req.lineoffsets[0] = gpio->num; 376 | req.lines = 1; 377 | 378 | if (strcmp(gpio->direction,"out") == 0) 379 | { 380 | req.default_values[0] = default_value; 381 | } 382 | 383 | int rc = ioctl(gpio->fd, GPIO_GET_LINEHANDLE_IOCTL, &req); 384 | if (rc < 0) 385 | { 386 | gpio_close(gpio); 387 | return GPIO_OPEN_ERROR; 388 | } 389 | gpio_close(gpio); 390 | gpio->fd = req.fd; 391 | 392 | return GPIO_OK; 393 | } 394 | 395 | void gpio_close(GPIO* gpio) 396 | { 397 | if(gpio->fd < 0) 398 | return; 399 | 400 | close(gpio->fd); 401 | gpio->fd = -1; 402 | } 403 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio.h: -------------------------------------------------------------------------------- 1 | #ifndef __OBJECTS_GPIO_UTILITIES_H__ 2 | #define __OBJECTS_GPIO_UTILITIES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct { 9 | gchar* name; 10 | gchar* dev; 11 | uint16_t num; 12 | uint16_t chip_id; 13 | gchar* direction; 14 | int fd; 15 | bool irq_inited; 16 | } GPIO; 17 | 18 | 19 | //gpio functions 20 | #define GPIO_OK 0x00 21 | #define GPIO_ERROR 0x01 22 | #define GPIO_OPEN_ERROR 0x02 23 | #define GPIO_INIT_ERROR 0x04 24 | #define GPIO_READ_ERROR 0x08 25 | #define GPIO_WRITE_ERROR 0x10 26 | #define GPIO_LOOKUP_ERROR 0x20 27 | 28 | void gpio_close(GPIO*); 29 | int gpio_open(GPIO*, uint8_t); 30 | int gpio_write(GPIO*, uint8_t); 31 | int gpio_get_params(GPIO*); 32 | int gpio_read(GPIO*,uint8_t*); 33 | void gpio_inits_done(); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio_configs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2016 Google Inc. 3 | * Copyright © 2016 IBM Corporation 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "gpio_configs.h" 19 | #include "gpio_json.h" 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | /** 29 | * Loads the GPIO information into the gpios->power_gpio structure 30 | * from the JSON. 31 | * 32 | * @param gpios - the structure where GpioConfigs.power_gpio will 33 | * be filled in. 34 | * @param gpio_configs - cJSON pointer to the GPIO JSON 35 | */ 36 | void read_power_gpios(GpioConfigs* gpios, const cJSON* gpio_configs) 37 | { 38 | size_t i = 0; 39 | 40 | const cJSON* power_config = cJSON_GetObjectItem( 41 | gpio_configs, "power_config"); 42 | g_assert(power_config != NULL); 43 | 44 | /* PGOOD - required */ 45 | 46 | const cJSON* pgood = cJSON_GetObjectItem(power_config, "power_good_in"); 47 | g_assert(pgood != NULL); 48 | 49 | gpios->power_gpio.power_good_in.name = g_strdup(pgood->valuestring); 50 | 51 | g_print("Power GPIO power good input: %s\n", 52 | gpios->power_gpio.power_good_in.name); 53 | 54 | /* Latch out - optional */ 55 | 56 | const cJSON* latch = cJSON_GetObjectItem(power_config, "latch_out"); 57 | if (latch != NULL) 58 | { 59 | gpios->power_gpio.latch_out.name = g_strdup(latch->valuestring); 60 | g_print("Power GPIO latch output: %s\n", 61 | gpios->power_gpio.latch_out.name); 62 | } 63 | else 64 | { 65 | //Must be NULL if not there 66 | gpios->power_gpio.latch_out.name = NULL; 67 | } 68 | 69 | /* Power Up Outs - required */ 70 | 71 | const cJSON* power_up_outs = cJSON_GetObjectItem( 72 | power_config, "power_up_outs"); 73 | g_assert(power_up_outs != NULL); 74 | 75 | gpios->power_gpio.num_power_up_outs = cJSON_GetArraySize(power_up_outs); 76 | g_print("Power GPIO %zu power_up outputs\n", 77 | gpios->power_gpio.num_power_up_outs); 78 | 79 | if (gpios->power_gpio.num_power_up_outs != 0) 80 | { 81 | gpios->power_gpio.power_up_outs = 82 | g_malloc0_n(gpios->power_gpio.num_power_up_outs, sizeof(GPIO)); 83 | gpios->power_gpio.power_up_pols = 84 | g_malloc0_n(gpios->power_gpio.num_power_up_outs, sizeof(gboolean)); 85 | 86 | const cJSON* power_out; 87 | cJSON_ArrayForEach(power_out, power_up_outs) 88 | { 89 | cJSON* name = cJSON_GetObjectItem(power_out, "name"); 90 | g_assert(name != NULL); 91 | gpios->power_gpio.power_up_outs[i].name = 92 | g_strdup(name->valuestring); 93 | 94 | const cJSON* polarity = cJSON_GetObjectItem(power_out, "polarity"); 95 | g_assert(polarity != NULL); 96 | gpios->power_gpio.power_up_pols[i] = polarity->valueint; 97 | 98 | g_print("Power GPIO power_up[%zd] = %s active %s\n", 99 | i, gpios->power_gpio.power_up_outs[i].name, 100 | gpios->power_gpio.power_up_pols[i] ? "HIGH" : "LOW"); 101 | i++; 102 | } 103 | } 104 | 105 | /* Resets - optional */ 106 | 107 | const cJSON* reset_outs = cJSON_GetObjectItem(power_config, "reset_outs"); 108 | gpios->power_gpio.num_reset_outs = cJSON_GetArraySize(reset_outs); 109 | 110 | g_print("Power GPIO %zu reset outputs\n", 111 | gpios->power_gpio.num_reset_outs); 112 | 113 | if (gpios->power_gpio.num_reset_outs != 0) 114 | { 115 | gpios->power_gpio.reset_outs = 116 | g_malloc0_n(gpios->power_gpio.num_reset_outs, sizeof(GPIO)); 117 | gpios->power_gpio.reset_pols = 118 | g_malloc0_n(gpios->power_gpio.num_reset_outs, sizeof(gboolean)); 119 | 120 | i = 0; 121 | const cJSON* reset_out; 122 | cJSON_ArrayForEach(reset_out, reset_outs) 123 | { 124 | cJSON* name = cJSON_GetObjectItem(reset_out, "name"); 125 | g_assert(name != NULL); 126 | gpios->power_gpio.reset_outs[i].name = g_strdup(name->valuestring); 127 | 128 | const cJSON* polarity = cJSON_GetObjectItem(reset_out, "polarity"); 129 | g_assert(polarity != NULL); 130 | gpios->power_gpio.reset_pols[i] = polarity->valueint; 131 | 132 | g_print("Power GPIO reset[%zd] = %s active %s\n", i, 133 | gpios->power_gpio.reset_outs[i].name, 134 | gpios->power_gpio.reset_pols[i] ? "HIGH" : "LOW"); 135 | i++; 136 | } 137 | } 138 | 139 | /* PCI Resets - optional */ 140 | 141 | const cJSON* pci_reset_outs = cJSON_GetObjectItem( 142 | power_config, "pci_reset_outs"); 143 | 144 | gpios->power_gpio.num_pci_reset_outs = 145 | cJSON_GetArraySize(pci_reset_outs); 146 | 147 | g_print("Power GPIO %zd pci reset outputs\n", 148 | gpios->power_gpio.num_pci_reset_outs); 149 | 150 | if (gpios->power_gpio.num_pci_reset_outs != 0) 151 | { 152 | gpios->power_gpio.pci_reset_outs = 153 | g_malloc0_n(gpios->power_gpio.num_pci_reset_outs, sizeof(GPIO)); 154 | gpios->power_gpio.pci_reset_pols = 155 | g_malloc0_n(gpios->power_gpio.num_pci_reset_outs, sizeof(gboolean)); 156 | gpios->power_gpio.pci_reset_holds = 157 | g_malloc0_n(gpios->power_gpio.num_pci_reset_outs, sizeof(gboolean)); 158 | 159 | i = 0; 160 | const cJSON* pci_reset_out; 161 | cJSON_ArrayForEach(pci_reset_out, pci_reset_outs) 162 | { 163 | cJSON* name = cJSON_GetObjectItem(pci_reset_out, "name"); 164 | g_assert(name != NULL); 165 | gpios->power_gpio.pci_reset_outs[i].name = 166 | g_strdup(name->valuestring); 167 | 168 | const cJSON* polarity = cJSON_GetObjectItem( 169 | pci_reset_out, "polarity"); 170 | g_assert(polarity != NULL); 171 | gpios->power_gpio.pci_reset_pols[i] = polarity->valueint; 172 | 173 | const cJSON* hold = cJSON_GetObjectItem(pci_reset_out, "hold"); 174 | g_assert(hold != NULL); 175 | gpios->power_gpio.pci_reset_holds[i] = polarity->valueint; 176 | 177 | g_print("Power GPIO pci reset[%zd] = %s active %s, hold %s\n", i, 178 | gpios->power_gpio.pci_reset_outs[i].name, 179 | gpios->power_gpio.pci_reset_pols[i] ? "HIGH" : "LOW", 180 | gpios->power_gpio.pci_reset_holds[i] ? "Yes" : "No"); 181 | i++; 182 | } 183 | } 184 | } 185 | 186 | gboolean read_gpios(GpioConfigs *gpios) 187 | { 188 | cJSON* json = load_json(); 189 | if (json == NULL) 190 | { 191 | return FALSE; 192 | } 193 | 194 | const cJSON* configs = cJSON_GetObjectItem(json, "gpio_configs"); 195 | g_assert(configs != NULL); 196 | 197 | read_power_gpios(gpios, configs); 198 | 199 | cJSON_Delete(json); 200 | return TRUE; 201 | } 202 | 203 | void free_gpios(GpioConfigs *gpios) { 204 | size_t i; 205 | g_free(gpios->power_gpio.latch_out.name); 206 | g_free(gpios->power_gpio.power_good_in.name); 207 | for(i = 0; i < gpios->power_gpio.num_power_up_outs; i++) { 208 | g_free(gpios->power_gpio.power_up_outs[i].name); 209 | } 210 | g_free(gpios->power_gpio.power_up_outs); 211 | g_free(gpios->power_gpio.power_up_pols); 212 | for(i = 0; i < gpios->power_gpio.num_reset_outs; i++) { 213 | g_free(gpios->power_gpio.reset_outs[i].name); 214 | } 215 | g_free(gpios->power_gpio.reset_outs); 216 | g_free(gpios->power_gpio.reset_pols); 217 | for(i = 0; i < gpios->power_gpio.num_pci_reset_outs; i++) { 218 | g_free(gpios->power_gpio.pci_reset_outs[i].name); 219 | } 220 | g_free(gpios->power_gpio.pci_reset_outs); 221 | g_free(gpios->power_gpio.pci_reset_pols); 222 | g_free(gpios->power_gpio.pci_reset_holds); 223 | } 224 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio_configs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2016 Google Inc. 3 | * Copyright © 2016 IBM Corporation 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __GPIO_CONFIGS_H__ 19 | #define __GPIO_CONFIGS_H__ 20 | 21 | #include 22 | #include 23 | #include "gpio.h" 24 | 25 | typedef struct PowerGpio { 26 | /* Optional active high pin enabling writes to latched power_up pins. */ 27 | GPIO latch_out; /* NULL name if not used. */ 28 | /* Active high pin that is asserted following successful host power up. */ 29 | GPIO power_good_in; 30 | /* Selectable polarity pins enabling host power rails. */ 31 | size_t num_power_up_outs; 32 | GPIO *power_up_outs; 33 | /* TRUE for active high */ 34 | gboolean *power_up_pols; 35 | /* Selectable polarity pins holding system complexes in reset. */ 36 | size_t num_reset_outs; 37 | GPIO *reset_outs; 38 | /* TRUE for active high */ 39 | gboolean *reset_pols; 40 | size_t num_pci_reset_outs; 41 | GPIO *pci_reset_outs; 42 | /* TRUE for active high */ 43 | gboolean *pci_reset_pols; 44 | gboolean *pci_reset_holds; 45 | } PowerGpio; 46 | 47 | typedef struct GpioConfigs { 48 | PowerGpio power_gpio; 49 | } GpioConfigs; 50 | 51 | /* Read system configuration for GPIOs. */ 52 | gboolean read_gpios(GpioConfigs *gpios); 53 | /* Frees internal buffers. Does not free parameter. Does not close GPIOs. */ 54 | void free_gpios(GpioConfigs *gpios); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio_json.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2018 IBM Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include "gpio_json.h" 19 | 20 | #define GPIO_FILE "/etc/default/obmc/gpio/gpio_defs.json" 21 | 22 | cJSON* load_json() 23 | { 24 | FILE* fd = fopen(GPIO_FILE, "r"); 25 | if (!fd) 26 | { 27 | fprintf(stderr, "Unable to open GPIO JSON file %s\n", GPIO_FILE); 28 | return NULL; 29 | } 30 | 31 | fseek(fd, 0, SEEK_END); 32 | size_t size = (size_t) ftell(fd); 33 | rewind(fd); 34 | 35 | char* data = malloc(size + 1); 36 | 37 | size_t rc = fread(data, 1, size, fd); 38 | fclose(fd); 39 | if (rc != size) 40 | { 41 | free(data); 42 | fprintf(stderr, "Only read %zd out of %zd bytes of GPIO file %s\n", 43 | rc, size, GPIO_FILE); 44 | return NULL; 45 | } 46 | 47 | data[size] = '\0'; 48 | cJSON* json = cJSON_Parse(data); 49 | free(data); 50 | 51 | if (json == NULL) 52 | { 53 | fprintf(stderr, "Failed parsing GPIO file %s\n", GPIO_FILE); 54 | 55 | const char* error_loc = cJSON_GetErrorPtr(); 56 | if (error_loc != NULL) 57 | { 58 | fprintf(stderr, "JSON error at %s\n", error_loc); 59 | } 60 | } 61 | return json; 62 | } 63 | -------------------------------------------------------------------------------- /libopenbmc_intf/gpio_json.h: -------------------------------------------------------------------------------- 1 | #ifndef __GPIO_JSON_H__ 2 | #define __GPIO_JSON_H__ 3 | 4 | #include 5 | 6 | /** 7 | * Loads the GPIO definitions from JSON into a cJSON structure. 8 | * 9 | * @return cjSON* - The structure with the GPIO info. Should be freed 10 | * with cJSON_Delete() when done. NULL is returned 11 | * if there was an error. 12 | */ 13 | cJSON* load_json(); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /libopenbmc_intf/meson.build: -------------------------------------------------------------------------------- 1 | gnome = import('gnome') 2 | 3 | openbmc_intf_src = gnome.gdbus_codegen( 4 | 'openbmc_intf', 5 | sources: 'openbmc_intf.xml', 6 | interface_prefix: 'org.openbmc', 7 | object_manager: true, 8 | ) 9 | 10 | libopenbmc_intf = library( 11 | 'libopenbmc_intf', 12 | 'gpio.c', 13 | 'gpio_configs.c', 14 | 'gpio_json.c', 15 | openbmc_intf_src, 16 | # The gdbus generated code cannot be compiled with -Wpedantic. 17 | c_args: '-Wno-pedantic', 18 | dependencies: [cjson_dep, gio_unix_dep, glib_dep], 19 | version: meson.project_version(), 20 | install: true, 21 | ) 22 | 23 | libopenbmc_intf_includes = include_directories('.') 24 | 25 | import('pkgconfig').generate( 26 | libopenbmc_intf, 27 | name: 'libopenbmc_intf', 28 | version: meson.project_version(), 29 | requires: [gio_unix_dep, glib_dep], 30 | description: '[deprecated] OpenBMC interface library from skeleton', 31 | ) 32 | -------------------------------------------------------------------------------- /libopenbmc_intf/openbmc.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPENBMC_H__ 2 | #define __OPENBMC_H__ 3 | 4 | #include 5 | #include 6 | 7 | //select which dbus 8 | #define DBUS_TYPE G_BUS_TYPE_SYSTEM 9 | 10 | // Macros 11 | #define GET_VARIANT(v) g_variant_get_variant(v) 12 | #define GET_VARIANT_D(v) g_variant_get_double(g_variant_get_variant(v)) 13 | #define GET_VARIANT_U(v) g_variant_get_uint32(g_variant_get_variant(v)) 14 | #define GET_VARIANT_B(v) g_variant_get_byte(g_variant_get_variant(v)) 15 | #define NEW_VARIANT_D(v) g_variant_new_variant(g_variant_new_double(v)) 16 | #define NEW_VARIANT_U(v) g_variant_new_variant(g_variant_new_uint32(v)) 17 | #define NEW_VARIANT_B(v) g_variant_new_variant(g_variant_new_byte(v)) 18 | #define VARIANT_COMPARE(x,y) g_variant_compare(GET_VARIANT(x),GET_VARIANT(y)) 19 | 20 | #ifdef __arm__ 21 | static inline void devmem(void* addr, uint32_t val) 22 | { 23 | printf("devmem %p = 0x%08x\n",addr,val); 24 | asm volatile("" : : : "memory"); 25 | *(volatile uint32_t *)addr = val; 26 | } 27 | static inline uint32_t devmem_read(void* addr) 28 | { 29 | asm volatile("" : : : "memory"); 30 | return *(volatile uint32_t *)addr; 31 | } 32 | //static inline devmem(uint32_t reg, uint32_t val) 33 | //{ 34 | // printf("devmem 0x%08x = 0x%08x\n",reg,val); 35 | // //void* r = (void*)reg; 36 | // write_reg(reg,val); 37 | //} 38 | #else 39 | static inline void devmem(uint32_t val, uint32_t reg) 40 | { 41 | (void) val; 42 | (void) reg; 43 | } 44 | static inline uint32_t devmem_read(void* addr) 45 | { 46 | (void) addr; 47 | return 0; 48 | } 49 | 50 | #endif 51 | 52 | typedef struct { 53 | gint argc; 54 | gchar **argv; 55 | GMainLoop *loop; 56 | gpointer user_data; 57 | 58 | } cmdline; 59 | 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /libopenbmc_intf/openbmc_intf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'skeleton', 3 | 'c', 4 | version: '1.0', 5 | default_options: [ 6 | 'buildtype=debugoptimized', 7 | 'warning_level=2', 8 | 'werror=true', 9 | ], 10 | ) 11 | 12 | cjson_dep = dependency('libcjson', fallback: 'cjson') 13 | gio_unix_dep = dependency('gio-unix-2.0') 14 | glib_dep = dependency('glib-2.0') 15 | libsystemd_dep = dependency('libsystemd') 16 | 17 | subdir('libopenbmc_intf') 18 | 19 | subdir('op-pwrctl') 20 | subdir('op-hostctl') 21 | -------------------------------------------------------------------------------- /op-flasher/Makefile: -------------------------------------------------------------------------------- 1 | BINS=flasher 2 | LDLIBS+=-lflash 3 | include ../gdbus.mk 4 | include ../rules.mk 5 | -------------------------------------------------------------------------------- /op-flasher/flasher_obj.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 IBM Corp. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | * implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | static const gchar* dbus_object_path = "/org/openbmc/control"; 40 | static const gchar* dbus_name = "org.openbmc.control.Flasher"; 41 | 42 | static GDBusObjectManagerServer *manager = NULL; 43 | 44 | #define __aligned(x) __attribute__((aligned(x))) 45 | 46 | #define FILE_BUF_SIZE 0x10000 47 | static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000); 48 | 49 | static struct blocklevel_device *bl; 50 | static struct ffs_handle *ffsh; 51 | 52 | static uint8_t FLASH_OK = 0; 53 | static uint8_t FLASH_ERROR = 0x01; 54 | static uint8_t FLASH_SETUP_ERROR = 0x02; 55 | 56 | static int 57 | erase_chip(void) 58 | { 59 | int rc = 0; 60 | 61 | printf("Erasing... (may take a while !) "); 62 | fflush(stdout); 63 | 64 | rc = arch_flash_erase_chip(bl); 65 | if(rc) { 66 | fprintf(stderr, "Error %d erasing chip\n", rc); 67 | return(rc); 68 | } 69 | 70 | printf("done !\n"); 71 | return(rc); 72 | } 73 | 74 | void 75 | flash_message(GDBusConnection* connection,char* obj_path,char* method, char* error_msg) 76 | { 77 | GDBusProxy *proxy; 78 | GError *error; 79 | GVariant *parm = NULL; 80 | error = NULL; 81 | proxy = g_dbus_proxy_new_sync(connection, 82 | G_DBUS_PROXY_FLAGS_NONE, 83 | NULL, /* GDBusInterfaceInfo* */ 84 | "org.openbmc.control.Flash", /* name */ 85 | obj_path, /* object path */ 86 | "org.openbmc.Flash", /* interface name */ 87 | NULL, /* GCancellable */ 88 | &error); 89 | g_assert_no_error(error); 90 | 91 | error = NULL; 92 | if(strcmp(method,"error")==0) { 93 | parm = g_variant_new("(s)",error_msg); 94 | } 95 | g_dbus_proxy_call_sync(proxy, 96 | method, 97 | parm, 98 | G_DBUS_CALL_FLAGS_NONE, 99 | -1, 100 | NULL, 101 | &error); 102 | 103 | g_assert_no_error(error); 104 | } 105 | 106 | static int 107 | program_file(FlashControl* flash_control, const char *file, uint32_t start, uint32_t size) 108 | { 109 | int fd, rc; 110 | ssize_t len; 111 | uint32_t actual_size = 0; 112 | 113 | fd = open(file, O_RDONLY); 114 | if(fd == -1) { 115 | perror("Failed to open file"); 116 | return(fd); 117 | } 118 | printf("About to program \"%s\" at 0x%08x..0x%08x !\n", 119 | file, start, size); 120 | 121 | printf("Programming & Verifying...\n"); 122 | //progress_init(size >> 8); 123 | unsigned int save_size = size; 124 | uint8_t last_progress = 0; 125 | while(size) { 126 | len = read(fd, file_buf, FILE_BUF_SIZE); 127 | if(len < 0) { 128 | perror("Error reading file"); 129 | return(1); 130 | } 131 | if(len == 0) 132 | break; 133 | if(len > size) 134 | len = size; 135 | size -= len; 136 | actual_size += len; 137 | rc = blocklevel_write(bl, start, file_buf, len); 138 | if(rc) { 139 | if(rc == FLASH_ERR_VERIFY_FAILURE) 140 | fprintf(stderr, "Verification failed for" 141 | " chunk at 0x%08x\n", start); 142 | else 143 | fprintf(stderr, "Flash write error %d for" 144 | " chunk at 0x%08x\n", rc, start); 145 | return(rc); 146 | } 147 | start += len; 148 | unsigned int percent = (100*actual_size/save_size); 149 | uint8_t progress = (uint8_t)(percent); 150 | if(progress != last_progress) { 151 | flash_control_emit_progress(flash_control,file,progress); 152 | last_progress = progress; 153 | } 154 | } 155 | close(fd); 156 | 157 | return(0); 158 | } 159 | 160 | static void 161 | flash_access_cleanup(void) 162 | { 163 | if(ffsh) 164 | ffs_close(ffsh); 165 | arch_flash_close(bl, NULL); 166 | } 167 | 168 | static int 169 | flash_access_setup(enum flash_access chip) 170 | { 171 | int rc; 172 | printf("Setting up flash\n"); 173 | 174 | rc = arch_flash_access(bl, chip); 175 | if (rc != chip) { 176 | fprintf(stderr, "Failed to select flash chip\n"); 177 | return FLASH_SETUP_ERROR; 178 | } 179 | 180 | rc = arch_flash_init(&bl, NULL, 1); 181 | if (rc) { 182 | fprintf(stderr, "Failed to init flash: %d\n", rc); 183 | return FLASH_SETUP_ERROR; 184 | } 185 | 186 | /* Setup cleanup function */ 187 | atexit(flash_access_cleanup); 188 | return FLASH_OK; 189 | } 190 | 191 | uint8_t 192 | flash(FlashControl* flash_control, enum flash_access chip, uint32_t address, char* write_file, char* obj_path) 193 | { 194 | int rc; 195 | printf("flasher: %s, BMC = %d, address = 0x%x\n", write_file, chip, address); 196 | 197 | /* Prepare for access */ 198 | rc = flash_access_setup(chip); 199 | if(rc) { 200 | return FLASH_SETUP_ERROR; 201 | } 202 | 203 | if(strcmp(write_file,"")!=0) 204 | { 205 | // If file specified but not size, get size from file 206 | struct stat stbuf; 207 | if(stat(write_file, &stbuf)) { 208 | perror("Failed to get file size"); 209 | return FLASH_ERROR; 210 | } 211 | uint32_t write_size = stbuf.st_size; 212 | rc = erase_chip(); 213 | if(rc) { 214 | return FLASH_ERROR; 215 | } 216 | rc = program_file(flash_control, write_file, address, write_size); 217 | if(rc) { 218 | return FLASH_ERROR; 219 | } 220 | 221 | printf("Flash done\n"); 222 | } 223 | return FLASH_OK; 224 | } 225 | 226 | static void 227 | on_bus_acquired(GDBusConnection *connection, 228 | const gchar *name, 229 | gpointer user_data) 230 | { 231 | cmdline *cmd = user_data; 232 | if(cmd->argc < 4) 233 | { 234 | g_print("flasher [flash name] [filename] [source object]\n"); 235 | g_main_loop_quit(cmd->loop); 236 | return; 237 | } 238 | printf("Starting flasher: %s,%s,%s,\n",cmd->argv[1],cmd->argv[2],cmd->argv[3]); 239 | ObjectSkeleton *object; 240 | manager = g_dbus_object_manager_server_new(dbus_object_path); 241 | gchar *s; 242 | s = g_strdup_printf("%s/%s",dbus_object_path,cmd->argv[1]); 243 | 244 | object = object_skeleton_new(s); 245 | g_free(s); 246 | 247 | FlashControl* flash_control = flash_control_skeleton_new(); 248 | object_skeleton_set_flash_control(object, flash_control); 249 | g_object_unref(flash_control); 250 | 251 | /* Export the object (@manager takes its own reference to @object) */ 252 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 253 | g_object_unref(object); 254 | 255 | /* Export all objects */ 256 | g_dbus_object_manager_server_set_connection(manager, connection); 257 | enum flash_access chip = PNOR_MTD; 258 | uint32_t address = 0; 259 | 260 | /* TODO: Look up all partitions from the device tree or /proc/mtd */ 261 | if(strcmp(cmd->argv[1],"bmc")==0) { 262 | chip = BMC_MTD; 263 | address = 0; 264 | } 265 | if(strcmp(cmd->argv[1],"bmc_ramdisk")==0) { 266 | chip = BMC_MTD; 267 | /* TODO: Look up from device tree or similar */ 268 | address = 0x300000; 269 | } 270 | if(strcmp(cmd->argv[1],"bmc_kernel")==0) { 271 | chip = BMC_MTD; 272 | /* TODO: Look up from device tree or similar */ 273 | address = 0x80000; 274 | } 275 | 276 | int rc = flash(flash_control, chip, address, cmd->argv[2], cmd->argv[3]); 277 | if(rc) { 278 | flash_message(connection,cmd->argv[3],"error","Flash Error"); 279 | } else { 280 | flash_message(connection,cmd->argv[3],"done",""); 281 | } 282 | 283 | //Object exits when done flashing 284 | g_main_loop_quit(cmd->loop); 285 | } 286 | 287 | int 288 | main(int argc, char *argv[]) 289 | { 290 | GMainLoop *loop; 291 | cmdline cmd; 292 | cmd.argc = argc; 293 | cmd.argv = argv; 294 | 295 | guint id; 296 | loop = g_main_loop_new(NULL, FALSE); 297 | cmd.loop = loop; 298 | 299 | id = g_bus_own_name(DBUS_TYPE, 300 | dbus_name, 301 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 302 | G_BUS_NAME_OWNER_FLAGS_REPLACE, 303 | on_bus_acquired, 304 | NULL, 305 | NULL, 306 | &cmd, 307 | NULL); 308 | 309 | g_main_loop_run(loop); 310 | 311 | g_bus_unown_name(id); 312 | g_main_loop_unref(loop); 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /op-hostctl/Makefile: -------------------------------------------------------------------------------- 1 | BINS=control_host 2 | include ../gdbus.mk 3 | include ../rules.mk 4 | -------------------------------------------------------------------------------- /op-hostctl/control_host_obj.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | /* ------------------------------------------------------------------------- */ 14 | static const gchar* dbus_object_path = "/org/openbmc/control"; 15 | static const gchar* instance_name = "host0"; 16 | static const gchar* dbus_name = "org.openbmc.control.Host"; 17 | 18 | static GDBusObjectManagerServer *manager = NULL; 19 | 20 | #define PPC_BIT32(bit) (0x80000000UL >> (bit)) 21 | 22 | #define FSI_EXTERNAL_MODE_PATH "/sys/devices/platform/gpio-fsi/external_mode" 23 | #define FSI_SCAN_PATH "/sys/class/fsi-master/fsi0/rescan" 24 | 25 | /* TODO: Change this over to the cfam path once the cfam chardev patches have landed */ 26 | #define FSI_RAW_PATH "/sys/class/fsi-master/fsi0/slave@00:00/raw" 27 | 28 | #define FSI_SCAN_DELAY_US 10000 29 | 30 | /* Attention registers */ 31 | #define FSI_A_SI1S 0x081c 32 | #define TRUE_MASK 0x100d 33 | #define INTERRUPT_STATUS_REG 0x100b 34 | 35 | /* SBE boot register and values */ 36 | #define SBE_VITAL 0x281c 37 | #define SBE_WARMSTART PPC_BIT32(0) 38 | #define SBE_HW_TRIGGER PPC_BIT32(2) 39 | #define SBE_UPDATE_1ST_NIBBLE PPC_BIT32(3) 40 | #define SBE_IMAGE_SELECT PPC_BIT32(8) 41 | #define SBE_UPDATE_3RD_NIBBLE PPC_BIT32(11) 42 | 43 | /* Once the side is selected and attention bits are set, this starts the SBE */ 44 | #define START_SBE (SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) 45 | 46 | /* Primary is first side. Golden is second side */ 47 | #define PRIMARY_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) 48 | #define GOLDEN_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \ 49 | SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE) 50 | 51 | static gboolean 52 | on_init(Control *control, 53 | GDBusMethodInvocation *invocation, 54 | gpointer user_data) 55 | { 56 | (void) user_data; 57 | control_complete_init(control,invocation); 58 | return TRUE; 59 | } 60 | 61 | static gint 62 | fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) 63 | { 64 | int rc; 65 | uint32_t val = htobe32(val_host); 66 | /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ 67 | uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); 68 | 69 | rc = lseek(fd, addr, SEEK_SET); 70 | if (rc < 0) { 71 | g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, 72 | strerror(errno)); 73 | return errno; 74 | }; 75 | 76 | rc = write(fd, &val, sizeof(val)); 77 | if (rc < 0) { 78 | g_print("ERROR HostControl: cfam write failed: %s\n", 79 | strerror(errno)); 80 | return errno; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | static int fsi_rescan(void) 87 | { 88 | char *one = "1"; 89 | int fd, rc; 90 | 91 | fd = open(FSI_SCAN_PATH, O_WRONLY); 92 | if (fd < 0) { 93 | g_print("ERROR HostControl: Failed to open path '%s': %s\n", 94 | FSI_SCAN_PATH, strerror(errno)); 95 | return errno; 96 | } 97 | rc = write(fd, one, sizeof(*one)); 98 | close(fd); 99 | if (rc < 0) { 100 | g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", 101 | strerror(errno)); 102 | return errno; 103 | } 104 | g_print("HostControl: Performing FSI scan (delay %d us)\n", 105 | FSI_SCAN_DELAY_US); 106 | usleep(FSI_SCAN_DELAY_US); 107 | 108 | return 0; 109 | } 110 | 111 | static gboolean 112 | on_boot(ControlHost *host, 113 | GDBusMethodInvocation *invocation, 114 | gpointer user_data) 115 | { 116 | (void) user_data; 117 | int rc, cfam_fd; 118 | 119 | if(control_host_get_debug_mode(host)==1) { 120 | int fd; 121 | char *one = "1"; 122 | g_print("Enabling debug mode; not booting host\n"); 123 | fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); 124 | if (fd < 0) { 125 | g_print("ERROR HostControl: Failed to open path '%s'\n", 126 | FSI_EXTERNAL_MODE_PATH); 127 | return TRUE; 128 | } 129 | rc = write(fd, one, sizeof(*one)); 130 | if (rc < 0) { 131 | g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", 132 | FSI_EXTERNAL_MODE_PATH); 133 | } 134 | close(fd); 135 | return TRUE; 136 | } 137 | g_print("Booting host\n"); 138 | 139 | rc = fsi_rescan(); 140 | if (rc < 0) 141 | return FALSE; 142 | 143 | cfam_fd = open(FSI_RAW_PATH, O_RDWR); 144 | if (cfam_fd < 0) { 145 | g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); 146 | return FALSE; 147 | } 148 | 149 | control_host_complete_boot(host,invocation); 150 | do { 151 | rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); 152 | rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); 153 | rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); 154 | if(rc) { break; } 155 | 156 | const gchar* flash_side = control_host_get_flash_side(host); 157 | g_print("Using %s side of the bios flash\n",flash_side); 158 | if(strcmp(flash_side,"primary")==0) { 159 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); 160 | } else if(strcmp(flash_side,"golden") == 0) { 161 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); 162 | } else { 163 | g_print("ERROR: Invalid flash side: %s\n",flash_side); 164 | rc = 0xff; 165 | 166 | } 167 | if(rc) { break; } 168 | 169 | rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); 170 | } while(0); 171 | if(rc) 172 | { 173 | g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); 174 | } 175 | /* Close file descriptor */ 176 | close(cfam_fd); 177 | 178 | control_host_emit_booted(host); 179 | 180 | return TRUE; 181 | } 182 | 183 | static void 184 | on_bus_acquired(GDBusConnection *connection, 185 | const gchar *name, 186 | gpointer user_data) 187 | { 188 | (void) name; 189 | (void) user_data; 190 | 191 | ObjectSkeleton *object; 192 | //g_print ("Acquired a message bus connection: %s\n",name); 193 | manager = g_dbus_object_manager_server_new(dbus_object_path); 194 | 195 | gchar *s; 196 | s = g_strdup_printf("%s/%s",dbus_object_path,instance_name); 197 | object = object_skeleton_new(s); 198 | g_free(s); 199 | 200 | ControlHost* control_host = control_host_skeleton_new(); 201 | object_skeleton_set_control_host(object, control_host); 202 | g_object_unref(control_host); 203 | 204 | Control* control = control_skeleton_new(); 205 | object_skeleton_set_control(object, control); 206 | g_object_unref(control); 207 | 208 | //define method callbacks here 209 | g_signal_connect(control_host, 210 | "handle-boot", 211 | G_CALLBACK(on_boot), 212 | object); /* user_data */ 213 | g_signal_connect(control, 214 | "handle-init", 215 | G_CALLBACK(on_init), 216 | NULL); /* user_data */ 217 | 218 | control_host_set_debug_mode(control_host,0); 219 | control_host_set_flash_side(control_host,"primary"); 220 | 221 | /* Export the object (@manager takes its own reference to @object) */ 222 | g_dbus_object_manager_server_set_connection(manager, connection); 223 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 224 | g_object_unref(object); 225 | } 226 | 227 | static void 228 | on_name_acquired(GDBusConnection *connection, 229 | const gchar *name, 230 | gpointer user_data) 231 | { 232 | (void) connection; 233 | (void) name; 234 | (void) user_data; 235 | // g_print ("Acquired the name %s\n", name); 236 | } 237 | 238 | static void 239 | on_name_lost(GDBusConnection *connection, 240 | const gchar *name, 241 | gpointer user_data) 242 | { 243 | (void) connection; 244 | (void) name; 245 | (void) user_data; 246 | // g_print ("Lost the name %s\n", name); 247 | } 248 | 249 | gint 250 | main(gint argc, gchar *argv[]) 251 | { 252 | GMainLoop *loop; 253 | cmdline cmd; 254 | cmd.argc = argc; 255 | cmd.argv = argv; 256 | 257 | guint id; 258 | loop = g_main_loop_new(NULL, FALSE); 259 | 260 | id = g_bus_own_name(DBUS_TYPE, 261 | dbus_name, 262 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 263 | G_BUS_NAME_OWNER_FLAGS_REPLACE, 264 | on_bus_acquired, 265 | on_name_acquired, 266 | on_name_lost, 267 | &cmd, 268 | NULL); 269 | 270 | g_main_loop_run(loop); 271 | 272 | g_bus_unown_name(id); 273 | g_main_loop_unref(loop); 274 | return 0; 275 | } 276 | -------------------------------------------------------------------------------- /op-hostctl/meson.build: -------------------------------------------------------------------------------- 1 | executable( 2 | 'control_host.exe', 3 | 'control_host_obj.c', 4 | include_directories: libopenbmc_intf_includes, 5 | link_with: libopenbmc_intf, 6 | dependencies: [gio_unix_dep, glib_dep], 7 | install: true, 8 | ) 9 | -------------------------------------------------------------------------------- /op-pwrctl/Makefile: -------------------------------------------------------------------------------- 1 | BINS=power_control 2 | SUBDIRS=pgood_wait 3 | include ../gdbus.mk 4 | include ../rules.mk 5 | -------------------------------------------------------------------------------- /op-pwrctl/meson.build: -------------------------------------------------------------------------------- 1 | executable( 2 | 'power_control.exe', 3 | 'power_control_obj.c', 4 | include_directories: libopenbmc_intf_includes, 5 | link_with: libopenbmc_intf, 6 | dependencies: [gio_unix_dep, glib_dep], 7 | install: true, 8 | ) 9 | 10 | subdir('pgood_wait') 11 | -------------------------------------------------------------------------------- /op-pwrctl/pgood_wait/.gitignore: -------------------------------------------------------------------------------- 1 | pgood_wait 2 | -------------------------------------------------------------------------------- /op-pwrctl/pgood_wait/Makefile: -------------------------------------------------------------------------------- 1 | BINS=pgood_wait 2 | BIN_SUFFIX="" 3 | include ../../sdbus.mk 4 | include ../../rules.mk 5 | -------------------------------------------------------------------------------- /op-pwrctl/pgood_wait/meson.build: -------------------------------------------------------------------------------- 1 | executable( 2 | 'pgood_wait', 3 | 'pgood_wait.c', 4 | dependencies: [libsystemd_dep], 5 | install: true, 6 | ) 7 | -------------------------------------------------------------------------------- /op-pwrctl/pgood_wait/pgood_wait.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2016 IBM Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* Copied from phosphor-objmgr to make the code compile. */ 25 | static const int mapper_busy_retries = 5; 26 | static const uint64_t mapper_busy_delay_interval_usec = 1000000; 27 | 28 | static void quit(int r, void *loop) 29 | { 30 | sd_event_exit((sd_event *)loop, r); 31 | } 32 | 33 | static int callback(sd_bus_message *m, void *user, sd_bus_error *error) 34 | { 35 | (void) error; 36 | 37 | sd_event *loop = user; 38 | int r; 39 | char *property = NULL; 40 | 41 | r = sd_bus_message_skip(m, "s"); 42 | if (r < 0) 43 | { 44 | fprintf(stderr, "Error skipping message fields: %s\n", 45 | strerror(-r)); 46 | quit(r, loop); 47 | return r; 48 | } 49 | 50 | r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 51 | if (r < 0) 52 | { 53 | fprintf(stderr, "Error entering container: %s\n", 54 | strerror(-r)); 55 | quit(r, loop); 56 | return r; 57 | } 58 | 59 | while ((r = sd_bus_message_enter_container( 60 | m, 61 | SD_BUS_TYPE_DICT_ENTRY, 62 | "sv")) > 0) 63 | { 64 | r = sd_bus_message_read(m, "s", &property); 65 | if (r < 0) 66 | { 67 | fprintf(stderr, "Error reading message: %s\n", 68 | strerror(-r)); 69 | quit(r, loop); 70 | return r; 71 | } 72 | 73 | if (strcmp(property, "pgood")) 74 | continue; 75 | 76 | quit(0, loop); 77 | break; 78 | } 79 | 80 | return 0; 81 | } 82 | 83 | static int get_object(sd_bus *conn, const char *obj, 84 | sd_bus_message **reply) 85 | { 86 | sd_bus_message *request = NULL; 87 | int r, retry = 0; 88 | 89 | r = sd_bus_message_new_method_call( 90 | conn, &request, "xyz.openbmc_project.ObjectMapper", 91 | "/xyz/openbmc_project/object_mapper", 92 | "xyz.openbmc_project.ObjectMapper", "GetObject"); 93 | if (r < 0) 94 | goto exit; 95 | 96 | r = sd_bus_message_append(request, "s", obj); 97 | if (r < 0) 98 | goto exit; 99 | r = sd_bus_message_append(request, "as", 0, NULL); 100 | if (r < 0) 101 | goto exit; 102 | 103 | while (true) 104 | { 105 | r = sd_bus_call(conn, request, 0, NULL, reply); 106 | if (r == -EBUSY || r == -ENOBUFS) 107 | { 108 | if (retry >= mapper_busy_retries) 109 | break; 110 | 111 | usleep(mapper_busy_delay_interval_usec * (1 << retry)); 112 | ++retry; 113 | continue; 114 | } 115 | break; 116 | } 117 | 118 | if (r < 0) 119 | goto exit; 120 | 121 | exit: 122 | sd_bus_message_unref(request); 123 | 124 | return r; 125 | } 126 | 127 | static int get_service(sd_bus *conn, const char *obj, char **service) 128 | { 129 | sd_bus_message *reply = NULL; 130 | const char *tmp; 131 | int r; 132 | 133 | r = get_object(conn, obj, &reply); 134 | if (r < 0) 135 | goto exit; 136 | 137 | r = sd_bus_message_enter_container(reply, 0, NULL); 138 | if (r < 0) 139 | goto exit; 140 | 141 | r = sd_bus_message_enter_container(reply, 0, NULL); 142 | if (r < 0) 143 | goto exit; 144 | 145 | r = sd_bus_message_read(reply, "s", &tmp); 146 | if (r < 0) 147 | goto exit; 148 | 149 | *service = strdup(tmp); 150 | 151 | exit: 152 | sd_bus_message_unref(reply); 153 | 154 | return r; 155 | } 156 | 157 | int main(int argc, char *argv[]) 158 | { 159 | static const char *matchfmt = 160 | "type='signal'," 161 | "interface='org.freedesktop.DBus.Properties'," 162 | "member='PropertiesChanged'," 163 | "arg0='org.openbmc.control.Power'," 164 | "path='%s'," 165 | "sender='%s'"; 166 | static const char *usage = 167 | "Usage: %s OBJECTPATH on|off\n"; 168 | static const size_t LEN = 256; 169 | 170 | sd_bus *conn = NULL; 171 | sd_event *loop = NULL; 172 | sd_bus_slot *slot = NULL; 173 | sd_bus_error error = SD_BUS_ERROR_NULL; 174 | char *service = NULL; 175 | int r, dest = -1, state; 176 | char match[LEN]; 177 | 178 | if (argc < 3) 179 | { 180 | fprintf(stderr, usage, argv[0]); 181 | exit(EXIT_FAILURE); 182 | } 183 | 184 | if (!strcmp(argv[2], "on")) 185 | dest = 1; 186 | if (!strcmp(argv[2], "off")) 187 | dest = 0; 188 | 189 | if (dest != 0 && dest != 1) 190 | { 191 | fprintf(stderr, usage, argv[0]); 192 | exit(EXIT_FAILURE); 193 | } 194 | 195 | r = sd_bus_default_system(&conn); 196 | if (r < 0) 197 | { 198 | fprintf(stderr, "Error connecting to system bus: %s\n", 199 | strerror(-r)); 200 | goto finish; 201 | } 202 | 203 | r = get_service(conn, argv[1], &service); 204 | if (r < 0) 205 | { 206 | fprintf(stderr, "Error obtaining host service: %s\n", 207 | strerror(-r)); 208 | goto finish; 209 | } 210 | 211 | r = sd_event_default(&loop); 212 | if (r < 0) 213 | { 214 | fprintf(stderr, "Error obtaining event loop: %s\n", 215 | strerror(-r)); 216 | goto finish; 217 | } 218 | 219 | r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL); 220 | if (r < 0) 221 | { 222 | fprintf(stderr, "Failed to attach system " 223 | "bus to event loop: %s\n", 224 | strerror(-r)); 225 | goto finish; 226 | } 227 | 228 | if (strlen(matchfmt) + strnlen(argv[1], LEN) > LEN) 229 | { 230 | r = -E2BIG; 231 | fprintf(stderr, "Error adding match rule: %s\n", 232 | strerror(-r)); 233 | goto finish; 234 | } 235 | 236 | sprintf(match, matchfmt, argv[1], service); 237 | 238 | r = sd_bus_add_match(conn, 239 | &slot, 240 | match, 241 | callback, 242 | loop); 243 | if (r < 0) 244 | { 245 | fprintf(stderr, "Error adding match rule: %s\n", 246 | strerror(-r)); 247 | goto finish; 248 | } 249 | 250 | r = sd_bus_get_property_trivial(conn, 251 | service, 252 | argv[1], 253 | "org.openbmc.control.Power", 254 | "pgood", 255 | &error, 256 | 'i', 257 | &state); 258 | if (r < 0) 259 | { 260 | fprintf(stderr, "Error getting property: %s\n", 261 | strerror(-r)); 262 | goto finish; 263 | } 264 | 265 | if (dest == state) 266 | goto finish; 267 | 268 | r = sd_event_loop(loop); 269 | if (r < 0) 270 | { 271 | fprintf(stderr, "Error starting event loop: %s\n", 272 | strerror(-r)); 273 | goto finish; 274 | } 275 | 276 | finish: 277 | exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); 278 | } 279 | -------------------------------------------------------------------------------- /op-pwrctl/power_control_obj.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* ------------------------------------------------------------------------- */ 16 | static const gchar* dbus_object_path = "/org/openbmc/control"; 17 | static const gchar* instance_name = "power0"; 18 | static const gchar* dbus_name = "org.openbmc.control.Power"; 19 | 20 | static int g_pci_reset_held = 1; 21 | 22 | static GpioConfigs g_gpio_configs; 23 | 24 | static GDBusObjectManagerServer *manager = NULL; 25 | 26 | time_t pgood_timeout_start = 0; 27 | 28 | // TODO: Change to interrupt driven instead of polling 29 | static gboolean 30 | poll_pgood(gpointer user_data) 31 | { 32 | ControlPower *control_power = object_get_control_power((Object*)user_data); 33 | Control* control = object_get_control((Object*)user_data); 34 | 35 | //send the heartbeat 36 | guint poll_int = control_get_poll_interval(control); 37 | if(poll_int == 0) 38 | { 39 | g_print("ERROR PowerControl: Poll interval cannot be 0\n"); 40 | return FALSE; 41 | } 42 | //handle timeout 43 | time_t current_time = time(NULL); 44 | if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power) 45 | && pgood_timeout_start != 0) 46 | { 47 | g_print("ERROR PowerControl: Pgood poll timeout\n"); 48 | // set timeout to 0 so timeout doesn't happen again 49 | control_power_set_pgood_timeout(control_power,0); 50 | pgood_timeout_start = 0; 51 | return TRUE; 52 | } 53 | uint8_t pgood_state; 54 | 55 | int rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in, 0); 56 | if(rc != GPIO_OK) { 57 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); 58 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", 59 | g_gpio_configs.power_gpio.power_good_in.name, rc); 60 | return FALSE; 61 | } 62 | rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state); 63 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); 64 | if(rc == GPIO_OK) 65 | { 66 | //if changed, set property and emit signal 67 | if(pgood_state != control_power_get_pgood(control_power)) 68 | { 69 | size_t i; 70 | uint8_t reset_state; 71 | control_power_set_pgood(control_power, pgood_state); 72 | if(pgood_state == 0) 73 | { 74 | control_power_emit_power_lost(control_power); 75 | g_pci_reset_held = 1; 76 | } 77 | else 78 | { 79 | control_power_emit_power_good(control_power); 80 | } 81 | 82 | for(i = 0; i < g_gpio_configs.power_gpio.num_reset_outs; i++) 83 | { 84 | GPIO *reset_out = &g_gpio_configs.power_gpio.reset_outs[i]; 85 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.reset_pols[i]; 86 | rc = gpio_open(reset_out, reset_state); 87 | if(rc != GPIO_OK) 88 | { 89 | gpio_close(reset_out); 90 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", 91 | reset_out->name, rc); 92 | continue; 93 | } 94 | 95 | g_print("PowerControl: pgood: %d, setting reset %s to %d\n", 96 | (int)pgood_state, reset_out->name, (int)reset_state); 97 | gpio_write(reset_out, reset_state); 98 | gpio_close(reset_out); 99 | } 100 | 101 | for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++) 102 | { 103 | GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i]; 104 | if(pgood_state == 1) 105 | { 106 | /* 107 | * When powering on, hold PCI reset until 108 | * the processor can forward clocks and control reset. 109 | */ 110 | if(g_gpio_configs.power_gpio.pci_reset_holds[i]) 111 | { 112 | g_print("Holding pci reset: %s\n", pci_reset_out->name); 113 | continue; 114 | } 115 | } 116 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i]; 117 | rc = gpio_open(pci_reset_out, reset_state); 118 | if(rc != GPIO_OK) 119 | { 120 | gpio_close(pci_reset_out); 121 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", 122 | pci_reset_out->name, rc); 123 | continue; 124 | } 125 | 126 | g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n", 127 | (int)pgood_state, pci_reset_out->name, (int)reset_state); 128 | gpio_write(pci_reset_out, reset_state); 129 | gpio_close(pci_reset_out); 130 | } 131 | } 132 | } else { 133 | g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n", 134 | g_gpio_configs.power_gpio.power_good_in.name, rc); 135 | //return false so poll won't get called anymore 136 | return FALSE; 137 | } 138 | //pgood is not at desired state yet 139 | if(pgood_state != control_power_get_state(control_power) && 140 | control_power_get_pgood_timeout(control_power) > 0) 141 | { 142 | if(pgood_timeout_start == 0 ) { 143 | pgood_timeout_start = current_time; 144 | } 145 | } 146 | else 147 | { 148 | pgood_timeout_start = 0; 149 | } 150 | return TRUE; 151 | } 152 | 153 | /* Handler for BootProgress signal from BootProgress sensor */ 154 | static void 155 | on_boot_progress(GDBusConnection *connection, 156 | const gchar *sender_name, 157 | const gchar *object_path, 158 | const gchar *interface_name, 159 | const gchar *signal_name, 160 | GVariant *parameters, 161 | gpointer user_data) 162 | { 163 | (void) connection; 164 | (void) sender_name; 165 | (void) object_path; 166 | (void) interface_name; 167 | (void) signal_name; 168 | (void) user_data; 169 | 170 | gchar *interface; 171 | GVariantIter *properties; 172 | GVariantIter *dummy; 173 | gchar *boot_progress = NULL; 174 | gchar *property; 175 | GVariant *value; 176 | uint8_t pgood_state; 177 | uint8_t reset_state; 178 | int rc; 179 | size_t i; 180 | int ignore; 181 | 182 | if(!parameters) 183 | return; 184 | 185 | /* prevent release again */ 186 | if(!g_pci_reset_held) 187 | return; 188 | 189 | g_variant_get(parameters, "(&sa{sv}as)", &interface, &properties, &dummy); 190 | for(i = 0; g_variant_iter_next(properties, "{&sv}", &property, &value); i++) 191 | { 192 | if (strcmp(property, "BootProgress") == 0) 193 | { 194 | gchar* tmp; 195 | g_variant_get(value, "&s", &tmp); 196 | boot_progress = g_strdup(tmp); 197 | g_print("BootProgress: %s\n", boot_progress); 198 | g_variant_unref(value); 199 | } 200 | } 201 | 202 | g_variant_iter_free(properties); 203 | g_variant_iter_free(dummy); 204 | if (boot_progress == NULL) 205 | return; 206 | 207 | /* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */ 208 | ignore = strcmp(boot_progress, 209 | "xyz.openbmc_project.State.Boot.Progress.ProgressStages.MotherboardInit") == 0; 210 | g_free(boot_progress); 211 | 212 | if (ignore) 213 | return; 214 | 215 | rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in, 0); 216 | if(rc != GPIO_OK) 217 | { 218 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); 219 | g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n", 220 | g_gpio_configs.power_gpio.power_good_in.name, rc); 221 | return; 222 | } 223 | rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state); 224 | gpio_close(&g_gpio_configs.power_gpio.power_good_in); 225 | if(rc != GPIO_OK || pgood_state != 1) 226 | return; 227 | 228 | for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++) 229 | { 230 | GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i]; 231 | 232 | if(!g_gpio_configs.power_gpio.pci_reset_holds[i]) 233 | continue; 234 | reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i]; 235 | rc = gpio_open(pci_reset_out, reset_state); 236 | if(rc != GPIO_OK) 237 | { 238 | gpio_close(pci_reset_out); 239 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", 240 | pci_reset_out->name, rc); 241 | continue; 242 | } 243 | 244 | g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n", 245 | (int)pgood_state, pci_reset_out->name, (int)reset_state); 246 | gpio_write(pci_reset_out, reset_state); 247 | gpio_close(pci_reset_out); 248 | g_print("Released pci reset: %s\n", pci_reset_out->name); 249 | } 250 | g_pci_reset_held = 0; 251 | } 252 | 253 | static gboolean 254 | on_set_power_state(ControlPower *pwr, 255 | GDBusMethodInvocation *invocation, 256 | guint state, 257 | gpointer user_data) 258 | { 259 | (void) user_data; 260 | PowerGpio *power_gpio = &g_gpio_configs.power_gpio; 261 | if(state > 1) 262 | { 263 | g_dbus_method_invocation_return_dbus_error(invocation, 264 | "org.openbmc.ControlPower.Error.Failed", 265 | "Invalid power state"); 266 | return TRUE; 267 | } 268 | // return from method call 269 | control_power_complete_set_power_state(pwr,invocation); 270 | if(state == (guint) control_power_get_state(pwr)) 271 | { 272 | g_print("Power already at requested state: %d\n",state); 273 | } 274 | else 275 | { 276 | int error = 0; 277 | do { 278 | size_t i; 279 | uint8_t power_up_out; 280 | for (i = 0; i < power_gpio->num_power_up_outs; i++) { 281 | GPIO *power_pin = &power_gpio->power_up_outs[i]; 282 | power_up_out = state ^ !power_gpio->power_up_pols[i]; 283 | error = gpio_open(power_pin, power_up_out); 284 | if(error != GPIO_OK) { 285 | gpio_close(power_pin); 286 | g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n", 287 | power_gpio->power_up_outs[i].name, error); 288 | continue; 289 | } 290 | g_print("PowerControl: setting power up %s to %d\n", 291 | power_gpio->power_up_outs[i].name, (int)power_up_out); 292 | error = gpio_write(power_pin, power_up_out); 293 | if(error != GPIO_OK) { 294 | gpio_close(power_pin); 295 | continue; 296 | } 297 | gpio_close(power_pin); 298 | } 299 | if(error != GPIO_OK) { break; } 300 | control_power_set_state(pwr,state); 301 | } while(0); 302 | if(error != GPIO_OK) 303 | { 304 | g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error); 305 | } 306 | 307 | /* If there's a latch, it should be enabled following changes to the 308 | * power pins' states. This commits the changes to the latch states. */ 309 | if (power_gpio->latch_out.name != NULL) { 310 | int rc; 311 | uint8_t latch_value = 1; 312 | rc = gpio_open(&power_gpio->latch_out, latch_value); 313 | if (rc != GPIO_OK) { 314 | /* Failures are non-fatal. */ 315 | gpio_close(&power_gpio->latch_out); 316 | g_print("PowerControl ERROR failed to open latch %s rc=%d\n", 317 | power_gpio->latch_out.name, rc); 318 | return TRUE; 319 | } 320 | /* Make the latch transparent for as brief of a time as possible. */ 321 | rc = gpio_write(&power_gpio->latch_out, latch_value--); 322 | if (rc != GPIO_OK) { 323 | g_print("PowerControl ERROR failed to assert latch %s rc=%d\n", 324 | power_gpio->latch_out.name, rc); 325 | } else { 326 | g_print("PowerControl asserted latch %s\n", 327 | power_gpio->latch_out.name); 328 | } 329 | rc = gpio_write(&power_gpio->latch_out, latch_value); 330 | if (rc != GPIO_OK) { 331 | g_print("PowerControl ERROR failed to clear latch %s rc=%d\n", 332 | power_gpio->latch_out.name, rc); 333 | } 334 | gpio_close(&power_gpio->latch_out); 335 | } 336 | } 337 | 338 | return TRUE; 339 | } 340 | 341 | static gboolean 342 | on_init(Control *control, 343 | GDBusMethodInvocation *invocation, 344 | gpointer user_data) 345 | { 346 | (void) user_data; 347 | pgood_timeout_start = 0; 348 | //guint poll_interval = control_get_poll_interval(control); 349 | //g_timeout_add(poll_interval, poll_pgood, user_data); 350 | control_complete_init(control,invocation); 351 | return TRUE; 352 | } 353 | 354 | static gboolean 355 | on_get_power_state(ControlPower *pwr, 356 | GDBusMethodInvocation *invocation, 357 | gpointer user_data) 358 | { 359 | (void) user_data; 360 | guint pgood = control_power_get_pgood(pwr); 361 | control_power_complete_get_power_state(pwr,invocation,pgood); 362 | return TRUE; 363 | } 364 | 365 | static int 366 | set_up_gpio(PowerGpio *power_gpio, ControlPower* control_power) 367 | { 368 | int error = GPIO_OK; 369 | int rc; 370 | size_t i; 371 | uint8_t pgood_state; 372 | 373 | // get gpio device paths 374 | if(power_gpio->latch_out.name != NULL) { /* latch is optional */ 375 | rc = gpio_get_params(&power_gpio->latch_out); 376 | if(rc != GPIO_OK) { 377 | error = rc; 378 | } 379 | } 380 | rc = gpio_get_params(&power_gpio->power_good_in); 381 | if(rc != GPIO_OK) { 382 | error = rc; 383 | } 384 | for(i = 0; i < power_gpio->num_power_up_outs; i++) { 385 | rc = gpio_get_params(&power_gpio->power_up_outs[i]); 386 | if(rc != GPIO_OK) { 387 | error = rc; 388 | } 389 | } 390 | for(i = 0; i < power_gpio->num_reset_outs; i++) { 391 | rc = gpio_get_params(&power_gpio->reset_outs[i]); 392 | if(rc != GPIO_OK) { 393 | error = rc; 394 | } 395 | } 396 | for(i = 0; i < power_gpio->num_pci_reset_outs; i++) { 397 | rc = gpio_get_params(&power_gpio->pci_reset_outs[i]); 398 | if(rc != GPIO_OK) { 399 | error = rc; 400 | } 401 | } 402 | 403 | gpio_inits_done(); 404 | 405 | rc = gpio_open(&power_gpio->power_good_in, 0); 406 | if(rc != GPIO_OK) { 407 | gpio_close(&power_gpio->power_good_in); 408 | return rc; 409 | } 410 | rc = gpio_read(&power_gpio->power_good_in, &pgood_state); 411 | if(rc != GPIO_OK) { 412 | gpio_close(&power_gpio->power_good_in); 413 | return rc; 414 | } 415 | gpio_close(&power_gpio->power_good_in); 416 | control_power_set_pgood(control_power, pgood_state); 417 | control_power_set_state(control_power, pgood_state); 418 | g_print("Pgood state: %d\n", pgood_state); 419 | 420 | return error; 421 | } 422 | 423 | static void 424 | on_bus_acquired(GDBusConnection *connection, 425 | const gchar *name, 426 | gpointer user_data) 427 | { 428 | (void) name; 429 | ObjectSkeleton *object; 430 | cmdline *cmd = user_data; 431 | if(cmd->argc < 3) 432 | { 433 | g_print("Usage: power_control.exe [poll interval] [timeout]\n"); 434 | return; 435 | } 436 | manager = g_dbus_object_manager_server_new(dbus_object_path); 437 | gchar *s; 438 | s = g_strdup_printf("%s/%s",dbus_object_path,instance_name); 439 | object = object_skeleton_new(s); 440 | g_free(s); 441 | 442 | ControlPower* control_power = control_power_skeleton_new(); 443 | object_skeleton_set_control_power(object, control_power); 444 | g_object_unref(control_power); 445 | 446 | Control* control = control_skeleton_new(); 447 | object_skeleton_set_control(object, control); 448 | g_object_unref(control); 449 | 450 | //define method callbacks here 451 | g_signal_connect(control_power, 452 | "handle-set-power-state", 453 | G_CALLBACK(on_set_power_state), 454 | object); /* user_data */ 455 | 456 | g_signal_connect(control_power, 457 | "handle-get-power-state", 458 | G_CALLBACK(on_get_power_state), 459 | NULL); /* user_data */ 460 | 461 | g_signal_connect(control, 462 | "handle-init", 463 | G_CALLBACK(on_init), 464 | object); /* user_data */ 465 | 466 | /* Listen for BootProgress signal from BootProgress sensor */ 467 | g_dbus_connection_signal_subscribe(connection, 468 | NULL, /* service */ 469 | "org.freedesktop.DBus.Properties", /* interface_name */ 470 | "PropertiesChanged", /* member: name of the signal */ 471 | "/xyz/openbmc_project/state/host0", /* obj path */ 472 | NULL, /* arg0 */ 473 | G_DBUS_SIGNAL_FLAGS_NONE, 474 | (GDBusSignalCallback) on_boot_progress, 475 | object, /* user data */ 476 | NULL ); 477 | 478 | /* Export the object (@manager takes its own reference to @object) */ 479 | g_dbus_object_manager_server_set_connection(manager, connection); 480 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 481 | g_object_unref(object); 482 | 483 | if(read_gpios(&g_gpio_configs) != TRUE) { 484 | g_print("ERROR PowerControl: could not read power GPIO configuration\n"); 485 | exit(-1); 486 | } 487 | 488 | int rc = set_up_gpio(&g_gpio_configs.power_gpio, control_power); 489 | if(rc != GPIO_OK) { 490 | g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc); 491 | exit(-1); 492 | } 493 | //start poll 494 | pgood_timeout_start = 0; 495 | int poll_interval = atoi(cmd->argv[1]); 496 | int pgood_timeout = atoi(cmd->argv[2]); 497 | if(poll_interval < 500 || pgood_timeout <5) { 498 | g_print("ERROR PowerControl: poll_interval < 500 or pgood_timeout < 5\n"); 499 | exit(-1); 500 | } else { 501 | control_set_poll_interval(control,poll_interval); 502 | control_power_set_pgood_timeout(control_power,pgood_timeout); 503 | g_timeout_add(poll_interval, poll_pgood, object); 504 | } 505 | } 506 | 507 | static void 508 | on_name_acquired(GDBusConnection *connection, 509 | const gchar *name, 510 | gpointer user_data) 511 | { 512 | (void) connection; 513 | (void) name; 514 | (void) user_data; 515 | } 516 | 517 | static void 518 | on_name_lost(GDBusConnection *connection, 519 | const gchar *name, 520 | gpointer user_data) 521 | { 522 | (void) connection; 523 | (void) name; 524 | (void) user_data; 525 | free_gpios(&g_gpio_configs); 526 | } 527 | 528 | /*----------------------------------------------------------------*/ 529 | /* Main Event Loop */ 530 | 531 | gint 532 | main(gint argc, gchar *argv[]) 533 | { 534 | GMainLoop *loop; 535 | cmdline cmd; 536 | cmd.argc = argc; 537 | cmd.argv = argv; 538 | 539 | guint id; 540 | loop = g_main_loop_new(NULL, FALSE); 541 | 542 | id = g_bus_own_name(DBUS_TYPE, 543 | dbus_name, 544 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 545 | G_BUS_NAME_OWNER_FLAGS_REPLACE, 546 | on_bus_acquired, 547 | on_name_acquired, 548 | on_name_lost, 549 | &cmd, 550 | NULL); 551 | 552 | g_main_loop_run(loop); 553 | 554 | g_bus_unown_name(id); 555 | g_main_loop_unref(loop); 556 | return 0; 557 | } 558 | -------------------------------------------------------------------------------- /py.mk: -------------------------------------------------------------------------------- 1 | PYTHON?=python 2 | all: 3 | $(PYTHON) setup.py build 4 | 5 | clean: 6 | rm -rf build 7 | 8 | install: all 9 | $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PREFIX) 10 | -------------------------------------------------------------------------------- /pychassisctl/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pychassisctl/chassis_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # TODO: openbmc/openbmc#2994 remove python 2 support 4 | try: # python 2 5 | import gobject 6 | except ImportError: # python 3 7 | from gi.repository import GObject as gobject 8 | 9 | import dbus 10 | import dbus.mainloop.glib 11 | import dbus.service 12 | from obmc.dbuslib.bindings import DbusObjectManager, DbusProperties, get_dbus 13 | 14 | DBUS_NAME = "org.openbmc.control.Chassis" 15 | OBJ_NAME = "/org/openbmc/control/chassis0" 16 | CONTROL_INTF = "org.openbmc.Control" 17 | 18 | MACHINE_ID = "/etc/machine-id" 19 | 20 | POWER_OFF = 0 21 | POWER_ON = 1 22 | 23 | BOOTED = 100 24 | 25 | 26 | class ChassisControlObject(DbusProperties, DbusObjectManager): 27 | def getUuid(self): 28 | uuid = "" 29 | try: 30 | with open(MACHINE_ID) as f: 31 | data = f.readline().rstrip("\n") 32 | if len(data) == 32: 33 | uuid = data 34 | else: 35 | print("ERROR: UUID is not formatted correctly: " + data) 36 | except Exception: 37 | print("ERROR: Unable to open uuid file: " + MACHINE_ID) 38 | 39 | return uuid 40 | 41 | def __init__(self, bus, name): 42 | super(ChassisControlObject, self).__init__(conn=bus, object_path=name) 43 | # load utilized objects 44 | self.dbus_objects = { 45 | "power_control": { 46 | "bus_name": "org.openbmc.control.Power", 47 | "object_name": "/org/openbmc/control/power0", 48 | "interface_name": "org.openbmc.control.Power", 49 | }, 50 | "host_services": { 51 | "bus_name": "org.openbmc.HostServices", 52 | "object_name": "/org/openbmc/HostServices", 53 | "interface_name": "org.openbmc.HostServices", 54 | }, 55 | "systemd": { 56 | "bus_name": "org.freedesktop.systemd1", 57 | "object_name": "/org/freedesktop/systemd1", 58 | "interface_name": "org.freedesktop.systemd1.Manager", 59 | }, 60 | } 61 | 62 | # uuid 63 | self.Set(DBUS_NAME, "uuid", self.getUuid()) 64 | self.Set(DBUS_NAME, "reboot", 0) 65 | 66 | bus.add_signal_receiver( 67 | self.power_button_signal_handler, 68 | dbus_interface="org.openbmc.Button", 69 | signal_name="Released", 70 | path="/org/openbmc/buttons/power0", 71 | ) 72 | bus.add_signal_receiver( 73 | self.long_power_button_signal_handler, 74 | dbus_interface="org.openbmc.Button", 75 | signal_name="PressedLong", 76 | path="/org/openbmc/buttons/power0", 77 | ) 78 | bus.add_signal_receiver( 79 | self.softreset_button_signal_handler, 80 | dbus_interface="org.openbmc.Button", 81 | signal_name="Released", 82 | path="/org/openbmc/buttons/reset0", 83 | ) 84 | 85 | bus.add_signal_receiver( 86 | self.host_watchdog_signal_handler, 87 | dbus_interface="org.openbmc.Watchdog", 88 | signal_name="WatchdogError", 89 | ) 90 | 91 | def getInterface(self, name): 92 | o = self.dbus_objects[name] 93 | obj = bus.get_object(o["bus_name"], o["object_name"], introspect=False) 94 | return dbus.Interface(obj, o["interface_name"]) 95 | 96 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 97 | def powerOn(self): 98 | print("Turn on power and boot") 99 | self.Set(DBUS_NAME, "reboot", 0) 100 | intf = self.getInterface("systemd") 101 | f = getattr(intf, "StartUnit") 102 | f.call_async("obmc-host-start@0.target", "replace") 103 | return None 104 | 105 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 106 | def powerOff(self): 107 | print("Turn off power") 108 | intf = self.getInterface("systemd") 109 | f = getattr(intf, "StartUnit") 110 | f.call_async("obmc-chassis-hard-poweroff@0.target", "replace") 111 | return None 112 | 113 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 114 | def softPowerOff(self): 115 | print("Soft off power") 116 | intf = self.getInterface("systemd") 117 | f = getattr(intf, "StartUnit") 118 | f.call_async("obmc-host-shutdown@0.target", "replace") 119 | return None 120 | 121 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 122 | def reboot(self): 123 | print("Rebooting") 124 | if self.getPowerState() != POWER_OFF: 125 | self.Set(DBUS_NAME, "reboot", 1) 126 | self.powerOff() 127 | return None 128 | 129 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 130 | def softReboot(self): 131 | print("Soft Rebooting") 132 | if self.getPowerState() != POWER_OFF: 133 | self.Set(DBUS_NAME, "reboot", 1) 134 | self.softPowerOff() 135 | return None 136 | 137 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 138 | def quiesce(self): 139 | intf = self.getInterface("systemd") 140 | f = getattr(intf, "StartUnit") 141 | f.call_async("obmc-host-quiesce@0.target", "replace") 142 | return None 143 | 144 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="i") 145 | def getPowerState(self): 146 | intf = self.getInterface("power_control") 147 | return intf.getPowerState() 148 | 149 | # Signal handler 150 | 151 | def power_button_signal_handler(self): 152 | # toggle power, power-on / soft-power-off 153 | state = self.getPowerState() 154 | if state == POWER_OFF: 155 | self.powerOn() 156 | elif state == POWER_ON: 157 | self.softPowerOff() 158 | 159 | def long_power_button_signal_handler(self): 160 | print("Long-press button, hard power off") 161 | self.powerOff() 162 | 163 | def softreset_button_signal_handler(self): 164 | self.softReboot() 165 | 166 | def host_watchdog_signal_handler(self): 167 | print("Watchdog Error, Going to quiesce") 168 | self.quiesce() 169 | 170 | 171 | if __name__ == "__main__": 172 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 173 | 174 | bus = get_dbus() 175 | obj = ChassisControlObject(bus, OBJ_NAME) 176 | mainloop = gobject.MainLoop() 177 | 178 | obj.unmask_signals() 179 | name = dbus.service.BusName(DBUS_NAME, bus) 180 | 181 | print("Running ChassisControlService") 182 | mainloop.run() 183 | -------------------------------------------------------------------------------- /pychassisctl/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pychassisctl/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pychassisctl", 5 | version="1.0", 6 | scripts=["chassis_control.py"], 7 | ) 8 | -------------------------------------------------------------------------------- /pydownloadmgr/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pydownloadmgr/download_manager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | # TODO: openbmc/openbmc#2994 remove python 2 support 6 | try: # python 2 7 | import gobject 8 | except ImportError: # python 3 9 | from gi.repository import GObject as gobject 10 | 11 | import subprocess 12 | 13 | import dbus 14 | import dbus.mainloop.glib 15 | import dbus.service 16 | from obmc.dbuslib.bindings import get_dbus 17 | 18 | FLASH_DOWNLOAD_PATH = "/tmp" 19 | DBUS_NAME = "org.openbmc.managers.Download" 20 | OBJ_NAME = "/org/openbmc/managers/Download" 21 | TFTP_PORT = 69 22 | 23 | 24 | class DownloadManagerObject(dbus.service.Object): 25 | def __init__(self, bus, name): 26 | dbus.service.Object.__init__(self, bus, name) 27 | bus.add_signal_receiver( 28 | self.DownloadHandler, 29 | dbus_interface="org.openbmc.Flash", 30 | signal_name="Download", 31 | path_keyword="path", 32 | ) 33 | bus.add_signal_receiver( 34 | self.TftpDownloadHandler, 35 | signal_name="TftpDownload", 36 | path_keyword="path", 37 | ) 38 | 39 | @dbus.service.signal(DBUS_NAME, signature="ss") 40 | def DownloadComplete(self, outfile, filename): 41 | print("Download Complete: " + outfile) 42 | return outfile 43 | 44 | @dbus.service.signal(DBUS_NAME, signature="s") 45 | def DownloadError(self, filename): 46 | pass 47 | 48 | def TftpDownloadHandler(self, ip, filename, path=None): 49 | try: 50 | filename = str(filename) 51 | print("Downloading: " + filename + " from " + ip) 52 | outfile = FLASH_DOWNLOAD_PATH + "/" + os.path.basename(filename) 53 | rc = subprocess.call( 54 | ["tftp", "-l", outfile, "-r", filename, "-g", ip] 55 | ) 56 | if rc == 0: 57 | self.DownloadComplete(outfile, filename) 58 | else: 59 | self.DownloadError(filename) 60 | 61 | except Exception as e: 62 | print("ERROR DownloadManager: " + str(e)) 63 | self.DownloadError(filename) 64 | 65 | # TODO: this needs to be deprecated. 66 | # Shouldn't call flash interface from here 67 | def DownloadHandler(self, url, filename, path=None): 68 | try: 69 | filename = str(filename) 70 | print("Downloading: " + filename + " from " + url) 71 | outfile = FLASH_DOWNLOAD_PATH + "/" + os.path.basename(filename) 72 | subprocess.call(["tftp", "-l", outfile, "-r", filename, "-g", url]) 73 | obj = bus.get_object("org.openbmc.control.Flash", path) 74 | intf = dbus.Interface(obj, "org.openbmc.Flash") 75 | intf.update(outfile) 76 | 77 | except Exception as e: 78 | print("ERROR DownloadManager: " + str(e)) 79 | obj = bus.get_object("org.openbmc.control.Flash", path) 80 | intf = dbus.Interface(obj, "org.openbmc.Flash") 81 | intf.error("Download Error: " + filename) 82 | 83 | 84 | if __name__ == "__main__": 85 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 86 | bus = get_dbus() 87 | obj = DownloadManagerObject(bus, OBJ_NAME) 88 | mainloop = gobject.MainLoop() 89 | name = dbus.service.BusName(DBUS_NAME, bus) 90 | 91 | print("Running Download Manager") 92 | mainloop.run() 93 | -------------------------------------------------------------------------------- /pydownloadmgr/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pydownloadmgr/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pydownloadmgr", 5 | version="1.0", 6 | scripts=["download_manager.py"], 7 | ) 8 | -------------------------------------------------------------------------------- /pyflashbmc/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pyflashbmc/bmc_update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # TODO: openbmc/openbmc#2994 remove python 2 support 4 | try: # python 2 5 | import gobject 6 | except ImportError: # python 3 7 | from gi.repository import GObject as gobject 8 | import dbus 9 | import dbus.service 10 | import dbus.mainloop.glib 11 | import subprocess 12 | import tempfile 13 | import shutil 14 | import tarfile 15 | import os 16 | from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager 17 | 18 | DBUS_NAME = "org.openbmc.control.BmcFlash" 19 | OBJ_NAME = "/org/openbmc/control/flash/bmc" 20 | DOWNLOAD_INTF = "org.openbmc.managers.Download" 21 | 22 | BMC_DBUS_NAME = "xyz.openbmc_project.State.BMC" 23 | BMC_OBJ_NAME = "/xyz/openbmc_project/state/bmc0" 24 | 25 | UPDATE_PATH = "/run/initramfs" 26 | 27 | 28 | def doExtract(members, files): 29 | for tarinfo in members: 30 | if tarinfo.name in files: 31 | yield tarinfo 32 | 33 | 34 | def save_fw_env(): 35 | fw_env = "/etc/fw_env.config" 36 | lines = 0 37 | files = [] 38 | envcfg = open(fw_env, "r") 39 | try: 40 | for line in envcfg.readlines(): 41 | # ignore lines that are blank or start with # 42 | if line.startswith("#"): 43 | continue 44 | if not len(line.strip()): 45 | continue 46 | fn = line.partition("\t")[0] 47 | files.append(fn) 48 | lines += 1 49 | finally: 50 | envcfg.close() 51 | if lines < 1 or lines > 2 or (lines == 2 and files[0] != files[1]): 52 | raise Exception("Error parsing %s\n" % fw_env) 53 | shutil.copyfile(files[0], os.path.join(UPDATE_PATH, "image-u-boot-env")) 54 | 55 | 56 | class BmcFlashControl(DbusProperties, DbusObjectManager): 57 | def __init__(self, bus, name): 58 | super(BmcFlashControl, self).__init__(conn=bus, object_path=name) 59 | 60 | self.Set(DBUS_NAME, "status", "Idle") 61 | self.Set(DBUS_NAME, "filename", "") 62 | self.Set(DBUS_NAME, "preserve_network_settings", True) 63 | self.Set(DBUS_NAME, "restore_application_defaults", False) 64 | self.Set(DBUS_NAME, "update_kernel_and_apps", False) 65 | self.Set(DBUS_NAME, "clear_persistent_files", False) 66 | self.Set(DBUS_NAME, "auto_apply", False) 67 | 68 | bus.add_signal_receiver( 69 | self.download_error_handler, signal_name="DownloadError" 70 | ) 71 | bus.add_signal_receiver( 72 | self.download_complete_handler, signal_name="DownloadComplete" 73 | ) 74 | 75 | self.update_process = None 76 | self.progress_name = None 77 | 78 | @dbus.service.method(DBUS_NAME, in_signature="ss", out_signature="") 79 | def updateViaTftp(self, ip, filename): 80 | self.Set(DBUS_NAME, "status", "Downloading") 81 | self.TftpDownload(ip, filename) 82 | 83 | @dbus.service.method(DBUS_NAME, in_signature="s", out_signature="") 84 | def update(self, filename): 85 | self.Set(DBUS_NAME, "filename", filename) 86 | self.download_complete_handler(filename, filename) 87 | 88 | @dbus.service.signal(DOWNLOAD_INTF, signature="ss") 89 | def TftpDownload(self, ip, filename): 90 | self.Set(DBUS_NAME, "filename", filename) 91 | pass 92 | 93 | # Signal handler 94 | def download_error_handler(self, filename): 95 | if filename == self.Get(DBUS_NAME, "filename"): 96 | self.Set(DBUS_NAME, "status", "Download Error") 97 | 98 | def download_complete_handler(self, outfile, filename): 99 | # do update 100 | if filename != self.Get(DBUS_NAME, "filename"): 101 | return 102 | 103 | print("Download complete. Updating...") 104 | 105 | self.Set(DBUS_NAME, "status", "Download Complete") 106 | copy_files = {} 107 | 108 | # determine needed files 109 | if not self.Get(DBUS_NAME, "update_kernel_and_apps"): 110 | copy_files["image-bmc"] = True 111 | else: 112 | copy_files["image-kernel"] = True 113 | copy_files["image-rofs"] = True 114 | 115 | if self.Get(DBUS_NAME, "restore_application_defaults"): 116 | copy_files["image-rwfs"] = True 117 | 118 | # make sure files exist in archive 119 | try: 120 | tar = tarfile.open(outfile, "r") 121 | files = {} 122 | for f in tar.getnames(): 123 | files[f] = True 124 | tar.close() 125 | for f in list(copy_files.keys()): 126 | if f not in files: 127 | raise Exception( 128 | "ERROR: File not found in update archive: " + f 129 | ) 130 | 131 | except Exception as e: 132 | print(str(e)) 133 | self.Set(DBUS_NAME, "status", "Unpack Error") 134 | return 135 | 136 | try: 137 | tar = tarfile.open(outfile, "r") 138 | tar.extractall(UPDATE_PATH, members=doExtract(tar, copy_files)) 139 | tar.close() 140 | 141 | if self.Get(DBUS_NAME, "clear_persistent_files"): 142 | print("Removing persistent files") 143 | try: 144 | os.unlink(UPDATE_PATH + "/whitelist") 145 | except OSError as e: 146 | if e.errno == errno.EISDIR: 147 | pass 148 | elif e.errno == errno.ENOENT: 149 | pass 150 | else: 151 | raise 152 | 153 | try: 154 | wldir = UPDATE_PATH + "/whitelist.d" 155 | 156 | for file in os.listdir(wldir): 157 | os.unlink(os.path.join(wldir, file)) 158 | except OSError as e: 159 | if e.errno == errno.EISDIR: 160 | pass 161 | else: 162 | raise 163 | 164 | if self.Get(DBUS_NAME, "preserve_network_settings"): 165 | print("Preserving network settings") 166 | save_fw_env() 167 | 168 | except Exception as e: 169 | print(str(e)) 170 | self.Set(DBUS_NAME, "status", "Unpack Error") 171 | 172 | self.Verify() 173 | 174 | def Verify(self): 175 | self.Set(DBUS_NAME, "status", "Checking Image") 176 | try: 177 | subprocess.check_call( 178 | [ 179 | "/run/initramfs/update", 180 | "--no-flash", 181 | "--no-save-files", 182 | "--no-restore-files", 183 | "--no-clean-saved-files", 184 | ] 185 | ) 186 | 187 | self.Set(DBUS_NAME, "status", "Image ready to apply.") 188 | if self.Get(DBUS_NAME, "auto_apply"): 189 | self.Apply() 190 | except Exception: 191 | self.Set(DBUS_NAME, "auto_apply", False) 192 | try: 193 | subprocess.check_output( 194 | [ 195 | "/run/initramfs/update", 196 | "--no-flash", 197 | "--ignore-mount", 198 | "--no-save-files", 199 | "--no-restore-files", 200 | "--no-clean-saved-files", 201 | ], 202 | stderr=subprocess.STDOUT, 203 | ) 204 | self.Set( 205 | DBUS_NAME, 206 | "status", 207 | "Deferred for mounted filesystem. reboot BMC to apply.", 208 | ) 209 | except subprocess.CalledProcessError as e: 210 | self.Set(DBUS_NAME, "status", "Verify error: %s" % e.output) 211 | except OSError as e: 212 | self.Set( 213 | DBUS_NAME, 214 | "status", 215 | "Verify error: problem calling update: %s" % e.strerror, 216 | ) 217 | 218 | def Cleanup(self): 219 | if self.progress_name: 220 | try: 221 | os.unlink(self.progress_name) 222 | self.progress_name = None 223 | except oserror as e: 224 | if e.errno == EEXIST: 225 | pass 226 | raise 227 | self.update_process = None 228 | self.Set(DBUS_NAME, "status", "Idle") 229 | 230 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 231 | def Abort(self): 232 | if self.update_process: 233 | try: 234 | self.update_process.kill() 235 | except Exception: 236 | pass 237 | for file in os.listdir(UPDATE_PATH): 238 | if file.startswith("image-"): 239 | os.unlink(os.path.join(UPDATE_PATH, file)) 240 | 241 | self.Cleanup() 242 | 243 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="s") 244 | def GetUpdateProgress(self): 245 | msg = "" 246 | 247 | if self.update_process and self.update_process.returncode is None: 248 | self.update_process.poll() 249 | 250 | if self.update_process is None: 251 | pass 252 | elif self.update_process.returncode > 0: 253 | self.Set(DBUS_NAME, "status", "Apply failed") 254 | elif self.update_process.returncode is None: 255 | pass 256 | else: # (self.update_process.returncode == 0) 257 | files = "" 258 | for file in os.listdir(UPDATE_PATH): 259 | if file.startswith("image-"): 260 | files = files + file 261 | if files == "": 262 | msg = "Apply Complete. Reboot to take effect." 263 | else: 264 | msg = "Apply Incomplete, Remaining:" + files 265 | self.Set(DBUS_NAME, "status", msg) 266 | 267 | msg = self.Get(DBUS_NAME, "status") + "\n" 268 | if self.progress_name: 269 | try: 270 | prog = open(self.progress_name, "r") 271 | for line in prog: 272 | # strip off initial sets of xxx\r here 273 | # ignore crlf at the end 274 | # cr will be -1 if no '\r' is found 275 | cr = line.rfind("\r", 0, -2) 276 | msg = msg + line[(cr + 1):] 277 | except OSError as e: 278 | if e.error == EEXIST: 279 | pass 280 | raise 281 | return msg 282 | 283 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 284 | def Apply(self): 285 | progress = None 286 | self.Set(DBUS_NAME, "status", "Writing images to flash") 287 | try: 288 | progress = tempfile.NamedTemporaryFile( 289 | delete=False, prefix="progress." 290 | ) 291 | self.progress_name = progress.name 292 | self.update_process = subprocess.Popen( 293 | ["/run/initramfs/update"], 294 | stdout=progress.file, 295 | stderr=subprocess.STDOUT, 296 | ) 297 | except Exception as e: 298 | try: 299 | progress.close() 300 | os.unlink(progress.name) 301 | self.progress_name = None 302 | except Exception: 303 | pass 304 | raise 305 | 306 | try: 307 | progress.close() 308 | except Exception: 309 | pass 310 | 311 | @dbus.service.method(DBUS_NAME, in_signature="", out_signature="") 312 | def PrepareForUpdate(self): 313 | subprocess.call( 314 | [ 315 | "fw_setenv", 316 | "openbmconce", 317 | "copy-files-to-ram copy-base-filesystem-to-ram", 318 | ] 319 | ) 320 | # Set the variable twice so that it is written to both environments of 321 | # the u-boot redundant environment variables since initramfs can only 322 | # read one of the environments. 323 | subprocess.call( 324 | [ 325 | "fw_setenv", 326 | "openbmconce", 327 | "copy-files-to-ram copy-base-filesystem-to-ram", 328 | ] 329 | ) 330 | self.Set(DBUS_NAME, "status", "Switch to update mode in progress") 331 | o = bus.get_object(BMC_DBUS_NAME, BMC_OBJ_NAME) 332 | intf = dbus.Interface(o, "org.freedesktop.DBus.Properties") 333 | intf.Set( 334 | BMC_DBUS_NAME, 335 | "RequestedBMCTransition", 336 | "xyz.openbmc_project.State.BMC.Transition.Reboot", 337 | ) 338 | 339 | 340 | if __name__ == "__main__": 341 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 342 | 343 | bus = get_dbus() 344 | obj = BmcFlashControl(bus, OBJ_NAME) 345 | mainloop = gobject.MainLoop() 346 | 347 | obj.unmask_signals() 348 | name = dbus.service.BusName(DBUS_NAME, bus) 349 | 350 | print("Running Bmc Flash Control") 351 | mainloop.run() 352 | -------------------------------------------------------------------------------- /pyflashbmc/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pyflashbmc/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pyflashbmc", 5 | version="1.0", 6 | scripts=["bmc_update.py"], 7 | ) 8 | -------------------------------------------------------------------------------- /pyinventorymgr/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pyinventorymgr/inventory_items.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | 6 | # TODO: openbmc/openbmc#2994 remove python 2 support 7 | try: # python 2 8 | import gobject 9 | except ImportError: # python 3 10 | from gi.repository import GObject as gobject 11 | import dbus 12 | import dbus.service 13 | import dbus.mainloop.glib 14 | import obmc.dbuslib.propertycacher as PropertyCacher 15 | from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager 16 | 17 | 18 | INTF_NAME = "org.openbmc.InventoryItem" 19 | DBUS_NAME = "org.openbmc.Inventory" 20 | 21 | FRUS = {} 22 | 23 | 24 | class Inventory(DbusProperties, DbusObjectManager): 25 | def __init__(self, bus, name): 26 | super(Inventory, self).__init__(conn=bus, object_path=name) 27 | 28 | 29 | class InventoryItem(DbusProperties): 30 | def __init__(self, bus, name, data): 31 | super(InventoryItem, self).__init__(conn=bus, object_path=name) 32 | 33 | self.name = name 34 | 35 | if "present" not in data: 36 | data["present"] = "False" 37 | if "fault" not in data: 38 | data["fault"] = "False" 39 | if "version" not in data: 40 | data["version"] = "" 41 | 42 | self.SetMultiple(INTF_NAME, data) 43 | 44 | # this will load properties from cache 45 | PropertyCacher.load(name, INTF_NAME, self.properties) 46 | 47 | @dbus.service.method(INTF_NAME, in_signature="a{sv}", out_signature="") 48 | def update(self, data): 49 | self.SetMultiple(INTF_NAME, data) 50 | PropertyCacher.save(self.name, INTF_NAME, self.properties) 51 | 52 | @dbus.service.method(INTF_NAME, in_signature="s", out_signature="") 53 | def setPresent(self, present): 54 | self.Set(INTF_NAME, "present", present) 55 | PropertyCacher.save(self.name, INTF_NAME, self.properties) 56 | 57 | @dbus.service.method(INTF_NAME, in_signature="s", out_signature="") 58 | def setFault(self, fault): 59 | self.Set(INTF_NAME, "fault", fault) 60 | PropertyCacher.save(self.name, INTF_NAME, self.properties) 61 | 62 | 63 | def getVersion(): 64 | version = "Error" 65 | with open("/etc/os-release", "r") as f: 66 | for line in f: 67 | p = line.rstrip("\n") 68 | parts = line.rstrip("\n").split("=") 69 | if parts[0] == "VERSION_ID": 70 | version = parts[1] 71 | version = version.strip('"') 72 | return version 73 | 74 | 75 | if __name__ == "__main__": 76 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 77 | bus = get_dbus() 78 | mainloop = gobject.MainLoop() 79 | obj_parent = Inventory(bus, "/org/openbmc/inventory") 80 | INVENTORY_FILE = os.path.join( 81 | sys.prefix, "share", "inventory", "inventory.json" 82 | ) 83 | 84 | if os.path.exists(INVENTORY_FILE): 85 | import json 86 | 87 | with open(INVENTORY_FILE, "r") as f: 88 | try: 89 | inv = json.load(f) 90 | except ValueError: 91 | print("Invalid JSON detected in " + INVENTORY_FILE) 92 | else: 93 | FRUS = inv 94 | else: 95 | try: 96 | import obmc_system_config as System 97 | 98 | FRUS = System.FRU_INSTANCES 99 | except ImportError: 100 | pass 101 | 102 | for f in list(FRUS.keys()): 103 | import obmc.inventory 104 | 105 | obj_path = f.replace("", obmc.inventory.INVENTORY_ROOT) 106 | obj = InventoryItem(bus, obj_path, FRUS[f]) 107 | obj_parent.add(obj_path, obj) 108 | 109 | # TODO: this is a hack to update bmc inventory item with version 110 | # should be done by flash object 111 | if FRUS[f]["fru_type"] == "BMC": 112 | version = getVersion() 113 | obj.update({"version": version}) 114 | 115 | obj_parent.unmask_signals() 116 | name = dbus.service.BusName(DBUS_NAME, bus) 117 | print("Running Inventory Manager") 118 | mainloop.run() 119 | -------------------------------------------------------------------------------- /pyinventorymgr/obmc/inventory/__init__.py: -------------------------------------------------------------------------------- 1 | INVENTORY_ROOT = "/org/openbmc/inventory" 2 | -------------------------------------------------------------------------------- /pyinventorymgr/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pyinventorymgr/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pyinventorymgr", 5 | version="1.0", 6 | packages=["obmc.inventory"], 7 | scripts=["sync_inventory_items.py"], 8 | ) 9 | -------------------------------------------------------------------------------- /pyinventorymgr/sync_inventory_items.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -u 2 | # 3 | # Copyright 2016 IBM Corporation 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | # implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import sys 19 | import os 20 | import dbus 21 | import uuid 22 | import argparse 23 | import subprocess 24 | import obmc.mapper 25 | import shutil 26 | 27 | INV_INTF_NAME = "xyz.openbmc_project.Inventory.Item.NetworkInterface" 28 | NET_DBUS_NAME = "org.openbmc.NetworkManager" 29 | NET_OBJ_NAME = "/org/openbmc/NetworkManager/Interface" 30 | CHS_DBUS_NAME = "org.openbmc.control.Chassis" 31 | CHS_INTF_NAME = "xyz.openbmc_project.Common.UUID" 32 | CHS_OBJ_NAME = "/org/openbmc/control/chassis0" 33 | PROP_INTF_NAME = "org.freedesktop.DBus.Properties" 34 | INVENTORY_ROOT = "/xyz/openbmc_project/inventory" 35 | NETWORK_ROOT = "/xyz/openbmc_project/network" 36 | ETHERNET_INTF_NAME = "xyz.openbmc_project.Network.EthernetInterface" 37 | MAC_INTF_NAME = "xyz.openbmc_project.Network.MACAddress" 38 | 39 | FRUS = {} 40 | 41 | # IEEE 802 MAC address mask for locally administered. 42 | # This means the admin has set the MAC and is no longer 43 | # the unique number set by the device manufacturer. 44 | MAC_LOCALLY_ADMIN_MASK = 0x20000000000 45 | 46 | 47 | # Get inventory MACAddress value. 48 | def get_bmc_mac_address(bus, prop): 49 | mapper = obmc.mapper.Mapper(bus) 50 | 51 | # Get the inventory subtree, limited 52 | # to objects that implement NetworkInterface. 53 | for path, info in mapper.get_subtree( 54 | path=INVENTORY_ROOT, interfaces=[INV_INTF_NAME] 55 | ).iteritems(): 56 | 57 | # Find a NetworkInterface with 'bmc' in the path. 58 | if "bmc" not in path: 59 | continue 60 | 61 | # Only expecting a single service to implement 62 | # NetworkInterface. Get the service connection 63 | # from the mapper response 64 | conn = info.keys()[0] 65 | 66 | # Get the inventory object implementing NetworkInterface. 67 | obj = bus.get_object(conn, path) 68 | 69 | # Get the MAC address 70 | mproxy = obj.get_dbus_method("Get", PROP_INTF_NAME) 71 | return mproxy(INV_INTF_NAME, prop) 72 | 73 | 74 | # Get Network Interface object. 75 | def get_network_interface_object(bus): 76 | mapper = obmc.mapper.Mapper(bus) 77 | 78 | # Get the network subtree, limited 79 | # to objects that implements EthernetInterface. 80 | for path, info in mapper.get_subtree( 81 | path=NETWORK_ROOT, interfaces=[ETHERNET_INTF_NAME] 82 | ).iteritems(): 83 | 84 | # Find the one which is having physical interface,it may happen 85 | # that vlan interface is there and we want the physical 86 | # interface here. 87 | if path.split("/")[-1].find("_") < 0: 88 | service = info.keys()[0] 89 | net_obj = bus.get_object(service, path) 90 | return net_obj 91 | 92 | 93 | # Get inventory UUID value. 94 | def get_uuid(bus, prop): 95 | mapper = obmc.mapper.Mapper(bus) 96 | 97 | # Get the inventory subtree, limited 98 | # to objects that implement UUID. 99 | resp = mapper.get_subtree(path=INVENTORY_ROOT, interfaces=[CHS_INTF_NAME]) 100 | 101 | # Only expecting a single object to implement UUID. 102 | try: 103 | path, info = resp.items()[0] 104 | except IndexError as e: 105 | return None 106 | 107 | # Only expecting a single service to implement 108 | # UUID. Get the service connection 109 | # from the mapper response 110 | conn = info.keys()[0] 111 | 112 | # Get the inventory object implementing UUID. 113 | obj = bus.get_object(conn, path) 114 | 115 | # Get the uuid 116 | mproxy = obj.get_dbus_method("Get", PROP_INTF_NAME) 117 | return mproxy(CHS_INTF_NAME, prop) 118 | 119 | 120 | # Get the value of the mac on the system (from u-boot) without ':' separators 121 | def get_sys_mac(obj): 122 | sys_mac = "" 123 | try: 124 | sys_mac = subprocess.check_output(["fw_printenv", "-n", "ethaddr"]) 125 | except Exception: 126 | # Handle when mac does not exist in u-boot 127 | return sys_mac 128 | return sys_mac 129 | 130 | 131 | # Replace the value of the system mac with the value of the inventory 132 | # MAC if the system MAC is not locally administered because this means 133 | # the system admin has purposely set the MAC 134 | def sync_mac(obj, inv_mac, sys_mac): 135 | if sys_mac: 136 | # Convert sys MAC to int to perform bitwise '&' 137 | sys_mac = sys_mac.replace(":", "") 138 | int_sys_mac = int(sys_mac, 16) 139 | else: 140 | # Set mac to 0 for when u-boot mac is not present 141 | int_sys_mac = 0 142 | if not int_sys_mac & MAC_LOCALLY_ADMIN_MASK: 143 | # Sys MAC is not locally administered, go replace it with inv value 144 | intf = dbus.Interface(obj, dbus.PROPERTIES_IFACE) 145 | intf.Set(MAC_INTF_NAME, "MACAddress", inv_mac) 146 | 147 | 148 | # Set sys uuid, this reboots the BMC for the value to take effect 149 | def set_sys_uuid(uuid): 150 | rc = subprocess.call(["fw_setenv", "uuid", uuid]) 151 | if rc == 0: 152 | print("Rebooting BMC to set uuid") 153 | # TODO Uncomment once sync from u-boot to /etc/machine-id is in place 154 | # Issue openbmc/openbmc#479 155 | # rc = subprocess.call(["reboot"]) 156 | else: 157 | print("Error setting uuid") 158 | 159 | 160 | if __name__ == "__main__": 161 | arg = argparse.ArgumentParser() 162 | arg.add_argument("-p") 163 | arg.add_argument("-s") 164 | 165 | opt = arg.parse_args() 166 | prop_name = opt.p 167 | sync_type = opt.s 168 | 169 | bus = dbus.SystemBus() 170 | if sync_type == "mac": 171 | inv_mac = get_bmc_mac_address(bus, prop_name) 172 | if not inv_mac: 173 | sys.exit(1) 174 | net_obj = get_network_interface_object(bus) 175 | if not net_obj: 176 | print("Unable to get the network object") 177 | sys.exit(1) 178 | sys_mac = get_sys_mac(net_obj) 179 | if inv_mac != sys_mac: 180 | print("Inventory MAC=%s,System MAC=%s" % (inv_mac, sys_mac)) 181 | sync_mac(net_obj, inv_mac, sys_mac) 182 | elif sync_type == "uuid": 183 | inv_uuid = get_uuid(bus, prop_name) 184 | if inv_uuid: 185 | inv_uuid = uuid.UUID(inv_uuid) 186 | chs_obj = bus.get_object(CHS_DBUS_NAME, CHS_OBJ_NAME) 187 | chs_uuid = get_sys_uuid(chs_obj) 188 | if inv_uuid != sys_uuid: 189 | set_sys_uuid(inv_uuid) 190 | -------------------------------------------------------------------------------- /pyipmitest/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pyipmitest/ipmi_debug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import subprocess 5 | import dbus 6 | import string 7 | import os 8 | import fcntl 9 | import glib 10 | import gobject 11 | import dbus.service 12 | import dbus.mainloop.glib 13 | 14 | DBUS_NAME = "org.openbmc.HostIpmi" 15 | OBJ_NAME = "/org/openbmc/HostIpmi/1" 16 | 17 | 18 | def header(seq, netfn, lun, cmd): 19 | return ("seq: 0x%02x\nnetfn: 0x%02x\n\nlun: 0x%02d\ncmd: 0x%02x\n") % ( 20 | seq, 21 | netfn, 22 | lun, 23 | cmd, 24 | ) 25 | 26 | 27 | def print_request(seq, netfn, lun, cmd, data): 28 | str = header(seq, netfn, lun, cmd) 29 | str += "data: [%s]" % ", ".join(["0x%02x" % x for x in data]) 30 | print(str) 31 | 32 | 33 | def print_response(seq, netfn, lun, cmd, cc, data): 34 | str = header(seq, netfn, lun, cmd) 35 | str += "cc: 0x%02x\ndata: [%s]" % ( 36 | cc, 37 | ", ".join(["0x%02x" % x for x in data]), 38 | ) 39 | print(str) 40 | 41 | 42 | class IpmiDebug(dbus.service.Object): 43 | def __init__(self, bus, name): 44 | dbus.service.Object.__init__(self, bus, name) 45 | 46 | @dbus.service.signal(DBUS_NAME, "yyyyay") 47 | def ReceivedMessage(self, seq, netfn, lun, cmd, data): 48 | print("IPMI packet from host:") 49 | print_request(seq, netfn, lun, cmd, data) 50 | 51 | @dbus.service.method(DBUS_NAME, "yyyyyay", "x") 52 | def sendMessage(self, seq, netfn, lun, cmd, ccode, data): 53 | print("IPMI packet sent to host:") 54 | print_response(seq, netfn, lun, cmd, ccode, data) 55 | return 0 56 | 57 | @dbus.service.method(DBUS_NAME) 58 | def setAttention(self): 59 | print("IPMI SMS_ATN set") 60 | 61 | 62 | class ConsoleReader(object): 63 | def __init__(self, ipmi_obj): 64 | self.buffer = "" 65 | self.seq = 0 66 | self.ipmi_obj = ipmi_obj 67 | flags = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL) 68 | flags |= os.O_NONBLOCK 69 | fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, flags) 70 | glib.io_add_watch(sys.stdin, glib.IO_IN, self.io_callback) 71 | 72 | def io_callback(self, fd, condition): 73 | chunk = fd.read() 74 | for char in chunk: 75 | self.buffer += char 76 | if char == "\n": 77 | self.line(self.buffer) 78 | self.buffer = "" 79 | 80 | return True 81 | 82 | def line(self, data): 83 | s = data.split(" ") 84 | if len(s) < 2: 85 | print("Not enough bytes to form a valid IPMI packet") 86 | return 87 | try: 88 | data = [int(c, 16) for c in s] 89 | except ValueError: 90 | return 91 | self.seq += 1 92 | self.ipmi_obj.ReceivedMessage(self.seq, data[0], 0, data[1], data[2:]) 93 | 94 | 95 | def main(): 96 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 97 | bus = dbus.SystemBus() 98 | obj = IpmiDebug(bus, OBJ_NAME) 99 | mainloop = gobject.MainLoop() 100 | r = ConsoleReader(obj) 101 | 102 | obj.unmask_signals() 103 | name = dbus.service.BusName(DBUS_NAME, bus) 104 | 105 | print( 106 | "Enter IPMI packet as hex values. First three bytes will be used" 107 | "as netfn and cmd.\nlun will be zero." 108 | ) 109 | mainloop.run() 110 | 111 | 112 | if __name__ == "__main__": 113 | sys.exit(main()) 114 | -------------------------------------------------------------------------------- /pyipmitest/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pyipmitest/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pyipmitest", 5 | version="1.0", 6 | scripts=["ipmi_debug.py"], 7 | ) 8 | -------------------------------------------------------------------------------- /pystatemgr/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pystatemgr/discover_system_state.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dbus 4 | 5 | dbus_objects = { 6 | "power": { 7 | "bus_name": "org.openbmc.control.Power", 8 | "object_name": "/org/openbmc/control/power0", 9 | "interface_name": "org.openbmc.control.Power", 10 | }, 11 | "occstatus0": { 12 | "bus_name": "org.openbmc.Sensors", 13 | "object_name": "/org/openbmc/sensors/host/cpu0/OccStatus", 14 | "interface_name": "org.openbmc.SensorValue", 15 | }, 16 | "occstatus1": { 17 | "bus_name": "org.openbmc.Sensors", 18 | "object_name": "/org/openbmc/sensors/host/cpu1/OccStatus", 19 | "interface_name": "org.openbmc.SensorValue", 20 | }, 21 | "bootprogress": { 22 | "bus_name": "org.openbmc.Sensors", 23 | "object_name": "/org/openbmc/sensors/host/BootProgress", 24 | "interface_name": "org.openbmc.SensorValue", 25 | }, 26 | "host": { 27 | "bus_name": "xyz.openbmc_project.State.Host", 28 | "object_name": "/xyz/openbmc_project/state/host0", 29 | "interface_name": "xyz.openbmc_project.State.Host", 30 | }, 31 | "settings": { 32 | "bus_name": "org.openbmc.settings.Host", 33 | "object_name": "/org/openbmc/settings/host0", 34 | "interface_name": "org.freedesktop.DBus.Properties", 35 | }, 36 | "system": { 37 | "bus_name": "org.openbmc.managers.System", 38 | "object_name": "/org/openbmc/managers/System", 39 | "interface_name": "org.freedesktop.DBus.Properties", 40 | }, 41 | "powersupplyredundancy": { 42 | "bus_name": "org.openbmc.Sensors", 43 | "object_name": "/org/openbmc/sensors/host/PowerSupplyRedundancy", 44 | "interface_name": "org.openbmc.SensorValue", 45 | }, 46 | "turboallowed": { 47 | "bus_name": "org.openbmc.Sensors", 48 | "object_name": "/org/openbmc/sensors/host/TurboAllowed", 49 | "interface_name": "org.openbmc.SensorValue", 50 | }, 51 | "powersupplyderating": { 52 | "bus_name": "org.openbmc.Sensors", 53 | "object_name": "/org/openbmc/sensors/host/PowerSupplyDerating", 54 | "interface_name": "org.openbmc.SensorValue", 55 | }, 56 | } 57 | 58 | 59 | def getInterface(bus, objs, key): 60 | obj = bus.get_object( 61 | objs[key]["bus_name"], objs[key]["object_name"], introspect=False 62 | ) 63 | return dbus.Interface(obj, objs[key]["interface_name"]) 64 | 65 | 66 | def getProperty(bus, objs, key, prop): 67 | obj = bus.get_object( 68 | objs[key]["bus_name"], objs[key]["object_name"], introspect=False 69 | ) 70 | intf = dbus.Interface(obj, dbus.PROPERTIES_IFACE) 71 | return intf.Get(objs[key]["interface_name"], prop) 72 | 73 | 74 | def setProperty(bus, objs, key, prop, prop_value): 75 | obj = bus.get_object(objs[key]["bus_name"], objs[key]["object_name"]) 76 | intf = dbus.Interface(obj, dbus.PROPERTIES_IFACE) 77 | return intf.Set(objs[key]["interface_name"], prop, prop_value) 78 | 79 | 80 | bus = dbus.SystemBus() 81 | pgood = getProperty(bus, dbus_objects, "power", "pgood") 82 | 83 | if pgood == 1: 84 | intf = getInterface(bus, dbus_objects, "bootprogress") 85 | intf.setValue("FW Progress, Starting OS") 86 | intf = getInterface(bus, dbus_objects, "occstatus0") 87 | intf.setValue("Enabled") 88 | intf = getInterface(bus, dbus_objects, "occstatus1") 89 | intf.setValue("Enabled") 90 | else: 91 | # Power is off, so check power policy 92 | settings_intf = getInterface(bus, dbus_objects, "settings") 93 | system_intf = getInterface(bus, dbus_objects, "system") 94 | system_last_state = system_intf.Get( 95 | "org.openbmc.managers.System", "system_last_state" 96 | ) 97 | power_policy = settings_intf.Get( 98 | "org.openbmc.settings.Host", "power_policy" 99 | ) 100 | print( 101 | "Last System State:" 102 | + system_last_state 103 | + "Power Policy:" 104 | + power_policy 105 | ) 106 | 107 | if power_policy == "ALWAYS_POWER_ON" or ( 108 | power_policy == "RESTORE_LAST_STATE" 109 | and system_last_state == "HOST_POWERED_ON" 110 | ): 111 | setProperty( 112 | bus, 113 | dbus_objects, 114 | "host", 115 | "RequestedHostTransition", 116 | "xyz.openbmc_project.State.Host.Transition.On", 117 | ) 118 | -------------------------------------------------------------------------------- /pystatemgr/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pystatemgr/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pystatemgr", 5 | version="1.0", 6 | scripts=["discover_system_state.py"], 7 | ) 8 | -------------------------------------------------------------------------------- /pysystemmgr/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pysystemmgr/obmc/system/__init__.py: -------------------------------------------------------------------------------- 1 | from glob import glob 2 | from os.path import join 3 | 4 | 5 | def find_gpio_base(path="/sys/class/gpio/"): 6 | pattern = "gpiochip*" 7 | for gc in glob(join(path, pattern)): 8 | with open(join(gc, "label")) as f: 9 | label = f.readline().strip() 10 | if label == "1e780000.gpio": 11 | with open(join(gc, "base")) as f: 12 | return int(f.readline().strip()) 13 | # trigger a file not found exception 14 | open(join(path, "gpiochip")) 15 | 16 | 17 | GPIO_BASE = find_gpio_base() 18 | 19 | 20 | def convertGpio(name): 21 | offset = int("".join(list(filter(str.isdigit, name)))) 22 | port = list(filter(str.isalpha, name.upper())) 23 | a = ord(port[-1]) - ord("A") 24 | if len(port) > 1: 25 | a += 26 26 | base = a * 8 + GPIO_BASE 27 | return base + offset 28 | -------------------------------------------------------------------------------- /pysystemmgr/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pysystemmgr/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pysystemmgr", 5 | version="1.0", 6 | packages=["obmc.system"], 7 | scripts=["system_manager.py"], 8 | ) 9 | -------------------------------------------------------------------------------- /pysystemmgr/system_manager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # TODO: openbmc/openbmc#2994 remove python 2 support 4 | try: # python 2 5 | import gobject 6 | except ImportError: # python 3 7 | from gi.repository import GObject as gobject 8 | import dbus 9 | import dbus.service 10 | import dbus.mainloop.glib 11 | import os 12 | from obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus 13 | import obmc.enums 14 | import obmc_system_config as System 15 | import obmc.inventory 16 | import obmc.system 17 | 18 | DBUS_NAME = "org.openbmc.managers.System" 19 | OBJ_NAME = "/org/openbmc/managers/System" 20 | INTF_SENSOR = "org.openbmc.SensorValue" 21 | 22 | 23 | class SystemManager(DbusProperties, DbusObjectManager): 24 | def __init__(self, bus, obj_name): 25 | super(SystemManager, self).__init__(conn=bus, object_path=obj_name) 26 | self.bus = bus 27 | 28 | # replace symbolic path in ID_LOOKUP 29 | for category in System.ID_LOOKUP: 30 | for key in System.ID_LOOKUP[category]: 31 | val = System.ID_LOOKUP[category][key] 32 | new_val = val.replace( 33 | "", obmc.inventory.INVENTORY_ROOT 34 | ) 35 | System.ID_LOOKUP[category][key] = new_val 36 | 37 | print("SystemManager Init Done") 38 | 39 | def doObjectLookup(self, category, key): 40 | obj_path = "" 41 | intf_name = INTF_SENSOR 42 | try: 43 | obj_path = System.ID_LOOKUP[category][key] 44 | parts = obj_path.split("/") 45 | if parts[3] != "sensors": 46 | print("ERROR SystemManager: SENSOR only supported type") 47 | intf_name = "" 48 | except Exception as e: 49 | print("ERROR SystemManager: " + str(e) + " not found in lookup") 50 | 51 | return [obj_path, intf_name] 52 | 53 | @dbus.service.method(DBUS_NAME, in_signature="ss", out_signature="(ss)") 54 | def getObjectFromId(self, category, key): 55 | return self.doObjectLookup(category, key) 56 | 57 | @dbus.service.method(DBUS_NAME, in_signature="sy", out_signature="(ss)") 58 | def getObjectFromByteId(self, category, key): 59 | byte = int(key) 60 | return self.doObjectLookup(category, byte) 61 | 62 | @dbus.service.method(DBUS_NAME, in_signature="s", out_signature="sis") 63 | def gpioInit(self, name): 64 | gpio_path = "" 65 | gpio_num = -1 66 | r = ["", gpio_num, ""] 67 | if name not in System.GPIO_CONFIG: 68 | # TODO: Better error handling 69 | msg = "ERROR: " + name + " not found in GPIO config table" 70 | print(msg) 71 | raise Exception(msg) 72 | else: 73 | 74 | gpio_num = -1 75 | gpio = System.GPIO_CONFIG[name] 76 | if "gpio_num" in System.GPIO_CONFIG[name]: 77 | gpio_num = gpio["gpio_num"] 78 | else: 79 | if "gpio_pin" in System.GPIO_CONFIG[name]: 80 | gpio_num = obmc.system.convertGpio(gpio["gpio_pin"]) 81 | else: 82 | msg = ( 83 | "ERROR: SystemManager - GPIO lookup failed for " + name 84 | ) 85 | print(msg) 86 | raise Exception(msg) 87 | 88 | if gpio_num != -1: 89 | r = [obmc.enums.GPIO_DEV, gpio_num, gpio["direction"]] 90 | return r 91 | 92 | @dbus.service.method( 93 | DBUS_NAME, in_signature="", out_signature="ssa(sb)a(sb)a(sbb)ssssa(sb)" 94 | ) 95 | def getGpioConfiguration(self): 96 | power_config = System.GPIO_CONFIGS.get("power_config", {}) 97 | power_good_in = power_config.get("power_good_in", "") 98 | latch_out = power_config.get("latch_out", "") 99 | power_up_outs = power_config.get("power_up_outs", []) 100 | reset_outs = power_config.get("reset_outs", []) 101 | pci_reset_outs = power_config.get("pci_reset_outs", []) 102 | hostctl_config = System.GPIO_CONFIGS.get("hostctl_config", {}) 103 | fsi_data = hostctl_config.get("fsi_data", "") 104 | fsi_clk = hostctl_config.get("fsi_clk", "") 105 | fsi_enable = hostctl_config.get("fsi_enable", "") 106 | cronus_sel = hostctl_config.get("cronus_sel", "") 107 | optionals = hostctl_config.get("optionals", []) 108 | r = [ 109 | power_good_in, 110 | latch_out, 111 | power_up_outs, 112 | reset_outs, 113 | pci_reset_outs, 114 | fsi_data, 115 | fsi_clk, 116 | fsi_enable, 117 | cronus_sel, 118 | optionals, 119 | ] 120 | print("Power GPIO config: " + str(r)) 121 | return r 122 | 123 | 124 | if __name__ == "__main__": 125 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 126 | bus = get_dbus() 127 | obj = SystemManager(bus, OBJ_NAME) 128 | mainloop = gobject.MainLoop() 129 | obj.unmask_signals() 130 | name = dbus.service.BusName(DBUS_NAME, bus) 131 | 132 | print("Running SystemManager") 133 | mainloop.run() 134 | -------------------------------------------------------------------------------- /pytools/Makefile: -------------------------------------------------------------------------------- 1 | ../Makefile.python -------------------------------------------------------------------------------- /pytools/gpioutil: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import getopt 6 | from glob import glob 7 | from os.path import join 8 | import obmc_system_config as System 9 | 10 | 11 | def printUsage(): 12 | print '\nUsage:' 13 | print 'gpioutil -n GPIO_NAME [-v value]' 14 | print 'gpioutil -i GPIO_NUM -d [-v value]' 15 | print 'gpioutil -p PIN_NAME -d [-v value]' 16 | print 'gpioutil -l PIN_NAME (lookup pin name only)' 17 | exit(1) 18 | 19 | 20 | 21 | if (len(sys.argv) < 2): 22 | printUsage() 23 | 24 | # Pop the command name and point to the args 25 | sys.argv.pop(0) 26 | 27 | GPIO_SYSFS = '/sys/class/gpio/' 28 | 29 | 30 | def find_gpio_base(path="/sys/class/gpio/"): 31 | pattern = "gpiochip*" 32 | for gc in glob(join(path, pattern)): 33 | with open(join(gc, "label")) as f: 34 | label = f.readline().strip() 35 | if label == "1e780000.gpio": 36 | with open(join(gc, "base")) as f: 37 | return int(f.readline().strip()) 38 | # trigger a file not found exception 39 | open(join(path, "gpiochip")) 40 | 41 | 42 | GPIO_BASE = find_gpio_base() 43 | 44 | 45 | def convertGpio(name): 46 | offset = int(''.join(list(filter(str.isdigit, name)))) 47 | port = list(filter(str.isalpha, name.upper())) 48 | a = ord(port[-1]) - ord('A') 49 | if len(port) > 1: 50 | a += 26 51 | base = a * 8 + GPIO_BASE 52 | return base + offset 53 | 54 | 55 | class Gpio: 56 | def __init__(self,gpio_num): 57 | self.gpio_num = str(gpio_num) 58 | self.direction = '' 59 | self.interrupt = '' 60 | self.exported = False 61 | 62 | def getPath(self,name): 63 | return GPIO_SYSFS+'gpio'+self.gpio_num+'/'+name 64 | 65 | def export(self): 66 | if (os.path.exists(GPIO_SYSFS+'export') == False): 67 | raise Exception("ERROR - GPIO_SYSFS path does not exist. Does this platform support GPIOS?") 68 | if (os.path.exists(GPIO_SYSFS+'gpio'+self.gpio_num) == False): 69 | self.write(GPIO_SYSFS+'export',self.gpio_num) 70 | 71 | self.exported = True 72 | 73 | def setDirection(self,dir): 74 | if (self.exported == False): 75 | raise Exception("ERROR - Not exported: "+self.getPath()) 76 | 77 | self.direction = '' 78 | self.interrupt = '' 79 | if (dir == 'in' or dir == 'out'): 80 | self.direction = dir 81 | elif (dir == 'rising' or 82 | dir == 'falling' or 83 | dir == 'both'): 84 | self.direction = 'in' 85 | self.interrupt = dir 86 | self.write(self.getPath('edge'),self.interrupt) 87 | else: 88 | raise Exception("ERROR - Invalid Direction: "+dir) 89 | 90 | current_direction = self.read(self.getPath('direction')) 91 | if current_direction != self.direction: 92 | self.write(self.getPath('direction'),self.direction) 93 | 94 | def setValue(self,value): 95 | if (value == '0'): 96 | self.write(self.getPath('value'),'0') 97 | elif (value == '1'): 98 | self.write(self.getPath('value'),'1') 99 | else: 100 | raise Exception("ERROR - Invalid value: "+value) 101 | 102 | def getValue(self): 103 | return self.read(self.getPath('value')) 104 | 105 | def write(self,path,data): 106 | f = open(path,'w') 107 | f.write(data) 108 | f.close() 109 | 110 | 111 | def read(self,path): 112 | f = open(path,'r') 113 | data = f.readline().strip() 114 | f.close() 115 | return data 116 | 117 | 118 | 119 | if __name__ == '__main__': 120 | 121 | try: 122 | opts, args = getopt.getopt(sys.argv,"hn:i:d:v:p:l:") 123 | except getopt.GetoptError: 124 | printUsage() 125 | 126 | 127 | 128 | lookup = False 129 | gpio_name = "" 130 | value = "" 131 | direction = "" 132 | for opt, arg in opts: 133 | if opt == '-h': 134 | printUsage() 135 | 136 | elif opt in ("-n"): 137 | gpio_name = arg 138 | lookup = True 139 | elif opt in ("-i"): 140 | gpio_name = arg 141 | elif opt in ("-d"): 142 | direction = arg 143 | elif opt in ("-v"): 144 | value = arg 145 | elif opt in ("-p"): 146 | gpio_name = convertGpio(arg) 147 | elif opt in ("-l"): 148 | gpio_name = convertGpio(arg) 149 | print gpio_name 150 | exit(0) 151 | 152 | gpio_info = {} 153 | if (lookup == True): 154 | if (System.GPIO_CONFIG.has_key(gpio_name) == False): 155 | print "ERROR - GPIO Name doesn't exist" 156 | print "Valid names: " 157 | for n in System.GPIO_CONFIG: 158 | print "\t"+n 159 | exit(0) 160 | gpio_info = System.GPIO_CONFIG[gpio_name] 161 | direction = gpio_info['direction'] 162 | if (gpio_info.has_key('gpio_num')): 163 | gpio_name = str(gpio_info['gpio_num']) 164 | else: 165 | gpio_name = str(convertGpio(gpio_info['gpio_pin'])) 166 | print "GPIO ID: "+gpio_name+"; DIRECTION: "+direction 167 | 168 | 169 | ## Rules 170 | if (gpio_name == ""): 171 | print "ERROR - Gpio not specified" 172 | printUsage() 173 | 174 | if (direction == "in" and value != ""): 175 | print "ERROR - Value cannot be specified when direction = in" 176 | printUsage() 177 | 178 | gpio = Gpio(gpio_name) 179 | try: 180 | gpio.export() 181 | if (direction != ""): 182 | gpio.setDirection(direction) 183 | 184 | if (value == ""): 185 | print gpio.getValue() 186 | else: 187 | gpio.setValue(value) 188 | 189 | except Exception as e: 190 | print e 191 | 192 | -------------------------------------------------------------------------------- /pytools/setup.cfg: -------------------------------------------------------------------------------- 1 | ../setup.cfg -------------------------------------------------------------------------------- /pytools/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="pytools", 5 | version="1.0", 6 | scripts=["gpioutil"], 7 | ) 8 | -------------------------------------------------------------------------------- /rules.mk: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := all 2 | sbindir=/usr/sbin 3 | 4 | LDLIBS+=$(shell pkg-config --libs $(PACKAGE_DEPS)) 5 | ALL_CFLAGS+=$(shell pkg-config --cflags $(PACKAGE_DEPS)) -fPIC -Werror $(CFLAGS) 6 | 7 | BIN_SUFFIX?=.exe 8 | .PHONY: $(SUBDIRS) 9 | 10 | all: $(BINS:=$(BIN_SUFFIX)) $(SUBDIRS) 11 | 12 | %.o: %.c 13 | $(CC) -c $(ALL_CFLAGS) -o $@ $< 14 | 15 | $(SUBDIRS): 16 | $(MAKE) -C $@ 17 | 18 | $(BINS:=$(BIN_SUFFIX)): %$(BIN_SUFFIX): %.o $(EXTRA_OBJS) 19 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 20 | 21 | install: $(BINS:=$(BIN_SUFFIX)) 22 | @mkdir -p $(DESTDIR)$(sbindir) 23 | @for b in $(BINS:=$(BIN_SUFFIX)); do \ 24 | install $$b $(DESTDIR)$(sbindir) || exit 1; \ 25 | done 26 | @for d in $(SUBDIRS); do \ 27 | $(MAKE) -C $$d $@ || exit 1; \ 28 | done 29 | 30 | clean: 31 | rm -rf *.o $(BINS:=$(BIN_SUFFIX)) 32 | @for d in $(SUBDIRS); do \ 33 | $(MAKE) -C $$d $@ || exit 1; \ 34 | done 35 | -------------------------------------------------------------------------------- /sdbus.mk: -------------------------------------------------------------------------------- 1 | PACKAGE_DEPS=libsystemd 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [install] 2 | install_scripts=/usr/sbin 3 | [pycodestyle] 4 | exclude=./configs/ 5 | -------------------------------------------------------------------------------- /subprojects/cjson.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = cJSON-1.7.18 3 | source_url = https://github.com/DaveGamble/cJSON/archive/refs/tags/v1.7.18.tar.gz 4 | source_filename = v1.7.18.tar.gz 5 | source_hash = 3aa806844a03442c00769b83e99970be70fbef03735ff898f4811dd03b9f5ee5 6 | patch_filename = cjson_1.7.18-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/cjson_1.7.18-1/get_patch 8 | patch_hash = a1068a4cc0b49f8bcbb6a841e7105f15a9a80a05449b842407561cf9f21e5101 9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/cjson_1.7.18-1/v1.7.18.tar.gz 10 | wrapdb_version = 1.7.18-1 11 | 12 | [provide] 13 | libcjson = libcjson_dep 14 | libcjson_utils = libcjson_utils_dep 15 | --------------------------------------------------------------------------------