summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/recipes-connectivity/lldp-util/lldp-util/src/LICENSE30
-rw-r--r--common/recipes-connectivity/lldp-util/lldp-util/src/Makefile19
-rw-r--r--common/recipes-connectivity/lldp-util/lldp-util/src/PATENTS23
-rw-r--r--common/recipes-connectivity/lldp-util/lldp-util/src/lldp_util.c703
-rw-r--r--common/recipes-connectivity/lldp-util/lldp-util_0.1.bb21
-rw-r--r--common/recipes-core/base-files/base-files_%.bbappend4
-rw-r--r--common/recipes-core/cfg-util/cfg-util_0.1.bb36
-rw-r--r--common/recipes-core/cfg-util/files/Makefile11
-rw-r--r--common/recipes-core/cfg-util/files/cfg-util.c78
-rw-r--r--common/recipes-core/consoled/consoled_0.1.bb36
-rw-r--r--common/recipes-core/consoled/files/Makefile11
-rw-r--r--common/recipes-core/consoled/files/consoled.c284
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/Makefile26
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/README5
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp1030
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp201
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/watchdog.h60
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb61
-rw-r--r--common/recipes-core/fruid/files/Makefile26
-rw-r--r--common/recipes-core/fruid/files/fruid-util.c145
-rw-r--r--common/recipes-core/fruid/fruid_0.1.bb55
-rw-r--r--common/recipes-core/ipmbd/files/Makefile10
-rw-r--r--common/recipes-core/ipmbd/files/ipmbd.c843
-rw-r--r--common/recipes-core/ipmbd/ipmbd_0.1.bb19
-rw-r--r--common/recipes-core/ipmid/files/Makefile29
-rw-r--r--common/recipes-core/ipmid/files/fruid.h28
-rw-r--r--common/recipes-core/ipmid/files/ipmid.c1412
-rw-r--r--common/recipes-core/ipmid/files/sdr.c414
-rw-r--r--common/recipes-core/ipmid/files/sdr.h72
-rw-r--r--common/recipes-core/ipmid/files/sel.c440
-rw-r--r--common/recipes-core/ipmid/files/sel.h51
-rw-r--r--common/recipes-core/ipmid/files/sensor.h117
-rw-r--r--common/recipes-core/ipmid/files/timestamp.c46
-rw-r--r--common/recipes-core/ipmid/files/timestamp.h30
-rw-r--r--common/recipes-core/ipmid/ipmid_0.2.bb42
-rw-r--r--common/recipes-core/power-util/files/Makefile11
-rw-r--r--common/recipes-core/power-util/files/power-util.c295
-rw-r--r--common/recipes-core/power-util/power-util_0.1.bb36
-rw-r--r--common/recipes-core/sensor-mon/files/Makefile26
-rw-r--r--common/recipes-core/sensor-mon/files/sensord.c1031
-rw-r--r--common/recipes-core/sensor-mon/sensor-mon_0.1.bb58
-rw-r--r--common/recipes-core/sensor-util/files/Makefile11
-rw-r--r--common/recipes-core/sensor-util/files/sensor-util.c173
-rw-r--r--common/recipes-core/sensor-util/sensor-util_0.1.bb34
-rw-r--r--common/recipes-core/watchdog-ctrl/watchdog-ctrl_0.1.bb15
-rw-r--r--common/recipes-lib/fruid/files/Makefile27
-rw-r--r--common/recipes-lib/fruid/files/fruid.c682
-rw-r--r--common/recipes-lib/fruid/files/fruid.h192
-rw-r--r--common/recipes-lib/fruid/libfruid_0.1.bb43
-rw-r--r--common/recipes-lib/gpio/files/src/Makefile27
-rw-r--r--common/recipes-lib/gpio/files/src/gpio.c107
-rw-r--r--common/recipes-lib/gpio/files/src/gpio.h42
-rw-r--r--common/recipes-lib/gpio/libgpio_0.1.bb40
-rw-r--r--common/recipes-lib/ipmb/files/Makefile11
-rw-r--r--common/recipes-lib/ipmb/files/ipmb.c82
-rw-r--r--common/recipes-lib/ipmb/files/ipmb.h75
-rw-r--r--common/recipes-lib/ipmb/libipmb_0.1.bb26
-rw-r--r--common/recipes-lib/ipmi/files/Makefile27
-rw-r--r--common/recipes-lib/ipmi/files/ipmi.c80
-rw-r--r--common/recipes-lib/ipmi/files/ipmi.h453
-rw-r--r--common/recipes-lib/ipmi/libipmi_0.2.bb41
-rw-r--r--common/recipes-lib/log/files/src/log.h59
-rw-r--r--common/recipes-lib/log/liblog_0.1.bb36
-rw-r--r--common/recipes-lib/sdr/files/Makefile11
-rw-r--r--common/recipes-lib/sdr/files/sdr.c210
-rw-r--r--common/recipes-lib/sdr/files/sdr.h163
-rw-r--r--common/recipes-lib/sdr/libsdr_0.1.bb30
-rw-r--r--common/recipes-rest/rest-api/files/node.py42
-rw-r--r--common/recipes-rest/rest-api/files/node_api.py31
-rw-r--r--common/recipes-rest/rest-api/files/node_bmc.py95
-rw-r--r--common/recipes-rest/rest-api/files/node_config.py65
-rw-r--r--common/recipes-rest/rest-api/files/node_fruid.py58
-rw-r--r--common/recipes-rest/rest-api/files/node_sensors.py60
-rw-r--r--common/recipes-rest/rest-api/files/node_server.py69
-rw-r--r--common/recipes-rest/rest-api/files/node_spb.py52
-rw-r--r--common/recipes-rest/rest-api/files/pal.py94
-rw-r--r--common/recipes-rest/rest-api/files/rest.py105
-rw-r--r--common/recipes-rest/rest-api/files/tree.py46
-rw-r--r--common/recipes-rest/rest-api/rest-api_0.2.bb36
-rw-r--r--common/recipes-utils/bitbang/bitbang_0.1.bb37
-rw-r--r--common/recipes-utils/bitbang/files/src/Makefile29
-rw-r--r--common/recipes-utils/bitbang/files/src/bitbang.c236
-rw-r--r--common/recipes-utils/bitbang/files/src/bitbang.h66
-rw-r--r--common/recipes-utils/bitbang/files/src/mdio_bb.c335
-rw-r--r--common/recipes-utils/bitbang/files/src/spi_bb.c317
-rw-r--r--common/recipes-utils/flashrom/files/01-include-make-local.patch11
-rw-r--r--common/recipes-utils/flashrom/files/flashrom-0.9.8/make.local9
-rw-r--r--common/recipes-utils/flashrom/flashrom_0.9.8.bb18
-rw-r--r--common/recipes-utils/jbi/files/code/COPYING340
-rw-r--r--common/recipes-utils/jbi/files/code/Makefile26
-rw-r--r--common/recipes-utils/jbi/files/code/jbicomp.c416
-rw-r--r--common/recipes-utils/jbi/files/code/jbicomp.h37
-rw-r--r--common/recipes-utils/jbi/files/code/jbiexprt.h224
-rw-r--r--common/recipes-utils/jbi/files/code/jbijtag.c1675
-rw-r--r--common/recipes-utils/jbi/files/code/jbijtag.h147
-rw-r--r--common/recipes-utils/jbi/files/code/jbimain.c3290
-rw-r--r--common/recipes-utils/jbi/files/code/jbiport.h45
-rw-r--r--common/recipes-utils/jbi/files/code/jbistub.c2222
-rw-r--r--common/recipes-utils/jbi/files/make/Microsoft/nmake.mak65
-rw-r--r--common/recipes-utils/jbi/files/make/PCVS/PVCS16.MAK61
-rw-r--r--common/recipes-utils/jbi/files/make/PCVS/pvcs32.mak61
-rw-r--r--common/recipes-utils/jbi/files/readme.openbmc5
-rw-r--r--common/recipes-utils/jbi/files/readme.txt464
-rw-r--r--common/recipes-utils/jbi/jbi_2.2.bb41
-rw-r--r--common/recipes-utils/openbmc-gpio/files/COPYING340
-rw-r--r--common/recipes-utils/openbmc-gpio/files/board_gpio_table.py23
-rw-r--r--common/recipes-utils/openbmc-gpio/files/openbmc_gpio.py164
-rw-r--r--common/recipes-utils/openbmc-gpio/files/openbmc_gpio_setup.py76
-rw-r--r--common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py269
-rw-r--r--common/recipes-utils/openbmc-gpio/files/openbmc_gpio_util.py153
-rw-r--r--common/recipes-utils/openbmc-gpio/files/phymemory.py100
-rw-r--r--common/recipes-utils/openbmc-gpio/files/setup.py36
-rw-r--r--common/recipes-utils/openbmc-gpio/files/soc_gpio.py19
-rw-r--r--common/recipes-utils/openbmc-gpio/files/soc_gpio_table.py23
-rw-r--r--common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb75
-rw-r--r--common/recipes-utils/openbmc-utils/files/COPYING340
-rw-r--r--common/recipes-utils/openbmc-utils/files/openbmc-utils.sh133
-rw-r--r--common/recipes-utils/openbmc-utils/openbmc-utils_0.1.bb48
-rw-r--r--common/recipes-utils/spatula/files/setup-spatula.sh80
-rw-r--r--common/recipes-utils/spatula/files/spatula_wrapper.py120
-rw-r--r--common/recipes-utils/spatula/spatula_0.1.bb47
121 files changed, 23546 insertions, 2 deletions
diff --git a/common/recipes-connectivity/lldp-util/lldp-util/src/LICENSE b/common/recipes-connectivity/lldp-util/lldp-util/src/LICENSE
new file mode 100644
index 0000000..a1dd699
--- /dev/null
+++ b/common/recipes-connectivity/lldp-util/lldp-util/src/LICENSE
@@ -0,0 +1,30 @@
+BSD License
+
+For OpenBMC lldp-util software
+
+Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/common/recipes-connectivity/lldp-util/lldp-util/src/Makefile b/common/recipes-connectivity/lldp-util/lldp-util/src/Makefile
new file mode 100644
index 0000000..8dfacfb
--- /dev/null
+++ b/common/recipes-connectivity/lldp-util/lldp-util/src/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+all: lldp-util
+
+# Yocto overrides anything we do to CFLAGS using "make -e",
+# so use our own EXTRA_CFLAGS variable instead of CFLAGS.
+EXTRA_CFLAGS = -std=gnu99 -Wall -Wextra -Werror \
+ -Wno-unused -Wno-unused-parameter
+
+lldp-util: lldp_util.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ @echo $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o lldp-util
diff --git a/common/recipes-connectivity/lldp-util/lldp-util/src/PATENTS b/common/recipes-connectivity/lldp-util/lldp-util/src/PATENTS
new file mode 100644
index 0000000..97e8932
--- /dev/null
+++ b/common/recipes-connectivity/lldp-util/lldp-util/src/PATENTS
@@ -0,0 +1,23 @@
+Additional Grant of Patent Rights
+
+"Software" means the OpenBMC lldp-util software distributed by Facebook, Inc.
+
+Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive,
+irrevocable (subject to the termination provision below) license under any
+rights in any patent claims owned by Facebook, to make, have made, use, sell,
+offer to sell, import, and otherwise transfer the Software. For avoidance of
+doubt, no license is granted under Facebook’s rights in any patent claims that
+are infringed by (i) modifications to the Software made by you or a third party,
+or (ii) the Software in combination with any software or other technology
+provided by you or a third party.
+
+The license granted hereunder will terminate, automatically and without notice,
+for anyone that makes any claim (including by filing any lawsuit, assertion or
+other action) alleging (a) direct, indirect, or contributory infringement or
+inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or
+affiliates, whether or not such claim is related to the Software, (ii) by any
+party if such claim arises in whole or in part from any software, product or
+service of Facebook or any of its subsidiaries or affiliates, whether or not
+such claim is related to the Software, or (iii) by any party relating to the
+Software; or (b) that any right in any patent claim of Facebook is invalid or
+unenforceable.
diff --git a/common/recipes-connectivity/lldp-util/lldp-util/src/lldp_util.c b/common/recipes-connectivity/lldp-util/lldp-util/src/lldp_util.c
new file mode 100644
index 0000000..a4ffc11
--- /dev/null
+++ b/common/recipes-connectivity/lldp-util/lldp-util/src/lldp_util.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * A simple utility for printing LLDP and CDP packets received on an interface.
+ * Eventually it might be worth replacing this with lldpd or lldpad,
+ * but for now this provides a simple standalone script that can be dropped
+ * onto a system and run on an as-needed basis.
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <linux/filter.h>
+#include <linux/if_ether.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// The minimum ethernet frame length, without the 4-byte frame check sequence
+#define MIN_FRAME_LENGTH 60
+#define MAX_FRAME_LENGTH 9000
+
+#define ETHERTYPE_VLAN 0x8100
+#define ETHERTYPE_LLDP 0x88CC
+
+#define LLDP_CHASSIS_CDP 0xff
+#define LLDP_CHASSIS_MAC_ADDRESS 4
+#define LLDP_CHASSIS_NET_ADDRESS 5
+
+#define LLDP_PORT_CDP 0xff
+#define LLDP_PORT_MAC_ADDRESS 3
+#define LLDP_PORT_NET_ADDRESS 4
+
+#define LLDP_TYPE_END 0
+#define LLDP_TYPE_CHASSIS_ID 1
+#define LLDP_TYPE_PORT_ID 2
+#define LLDP_TYPE_SYSTEM_NAME 5
+
+#define CDP_TYPE_DEVICE_ID 1
+#define CDP_TYPE_PORT_ID 3
+#define CDP_TYPE_SYSTEM_NAME 20
+
+static const unsigned char MAC_LLDP_NEAREST_BRIDGE[] =
+ { 0x01, 0x80, 0xc2, 0x00, 0x00,0x0e };
+static const unsigned char MAC_CDP[] =
+ { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
+
+static bool verbose = false;
+
+void errmsg(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
+void debugmsg(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
+
+void errmsg(const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+void debugmsg(const char* fmt, ...) {
+ if (!verbose) {
+ return;
+ }
+
+ va_list ap;
+ va_start(ap, fmt);
+ fputs("DEBUG: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+#define FAIL_ERRNO(msg, ...) \
+ do { \
+ returnCode = -errno; \
+ errmsg((msg), ##__VA_ARGS__); \
+ goto error; \
+ } while (0)
+
+#define CHECK_ERROR(rc, msg, ...) \
+ do { if ((rc) == -1) { FAIL_ERRNO((msg), ##__VA_ARGS__); } } while (0)
+
+typedef struct {
+ const char* protocol;
+ const char* local_interface;
+ const uint8_t* src_mac;
+ const uint8_t* chassis_id;
+ const uint8_t* port_id;
+ const uint8_t* system_name;
+ uint32_t chassis_id_length;
+ uint32_t port_id_length;
+ uint32_t system_name_length;
+ uint8_t chassis_id_type;
+ uint8_t port_id_type;
+} lldp_neighbor_t;
+
+
+#define DFLT_MAX_SAV_CDP 10
+
+typedef struct {
+ uint8_t *cdp_buf;
+ size_t length;
+} cdp_frame_t;
+
+typedef struct {
+ int max_sav_cdp; // max # cdp frames to save
+ int num_sav_cdp; // number currently saved
+ cdp_frame_t* frame; // saved CDP frames
+} cdp_sav_data_t;
+
+cdp_sav_data_t cdp_sav_data;
+
+volatile sig_atomic_t g_interrupt; // set in exit handler
+
+void lldp_neighbor_init(lldp_neighbor_t* neighbor,
+ const char* protocol,
+ const char* interface,
+ const uint8_t* src_mac) {
+ memset(neighbor, 0, sizeof(*neighbor));
+ neighbor->protocol = protocol;
+ neighbor->local_interface = interface;
+ neighbor->src_mac = src_mac;
+}
+
+int lldp_open(const char* interface) {
+ int fd = -1;
+ int returnCode = -EINVAL;
+
+ {
+ fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (fd < 0) {
+ FAIL_ERRNO("failed to create socket for local interface %s", interface);
+ }
+
+ // Look up the interface index
+ struct ifreq ifr;
+ snprintf(ifr.ifr_name, IFNAMSIZ, interface);
+ int rc = ioctl(fd, SIOCGIFINDEX, &ifr);
+ CHECK_ERROR(rc, "failed to get interface index for %s", interface);
+
+ // Bind the socket
+ struct sockaddr_ll addr;
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ addr.sll_protocol = htons(ETH_P_ALL);
+ rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
+ CHECK_ERROR(rc, "failed to bind socket for %s", interface);
+
+ // Ask linux to also send us packets sent to LLDP "nearest bridge"
+ // multicast MAC address
+ struct packet_mreq mr;
+ memset(&mr, 0, sizeof(mr));
+ mr.mr_ifindex = ifr.ifr_ifindex;
+ mr.mr_alen = ETH_ALEN;
+ memcpy(mr.mr_address, MAC_LLDP_NEAREST_BRIDGE, ETH_ALEN);
+ mr.mr_type = PACKET_MR_MULTICAST;
+ rc = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr));
+ CHECK_ERROR(rc, "failed to add LLDP packet membership for %s", interface);
+
+ // Ask linux to also send us packets sent to the CDP multicast MAC address
+ memcpy(mr.mr_address, MAC_CDP, ETH_ALEN);
+ rc = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr));
+ CHECK_ERROR(rc, "failed to add CDP packet membership for %s", interface);
+
+ // Set a filter to ignore non-multicast packets, so we don't get a flood
+ // of meaningless packets that we don't care about.
+ //
+ // tcpdump -i eth0 -dd ether multicast
+ static struct sock_filter PACKET_FILTER[] = {
+ { 0x30, 0, 0, 0x00000000 },
+ { 0x45, 0, 1, 0x00000001 },
+ { 0x6, 0, 0, 0x0000ffff },
+ { 0x6, 0, 0, 0x00000000 },
+ };
+ struct sock_fprog bpf;
+ bpf.len = sizeof(PACKET_FILTER) / sizeof(PACKET_FILTER[0]);
+ bpf.filter = PACKET_FILTER;
+ rc = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
+ CHECK_ERROR(rc, "failed to set socket packet filter for %s", interface);
+
+ returnCode = fd;
+ goto cleanup;
+ }
+
+error:
+ assert(returnCode < 0);
+ if (fd != -1) {
+ close(fd);
+ }
+
+cleanup:
+ return returnCode;
+}
+
+void lldp_print_value(const uint8_t* buf, uint32_t length) {
+ int n;
+
+ bool add_quotes = false;
+ for (uint32_t n = 0; n < length; ++n) {
+ uint8_t value = buf[n];
+ if (value < 0x20 || value >= 0x7f || isspace(value)) {
+ add_quotes = true;
+ break;
+ }
+ }
+
+ if (add_quotes) {
+ putchar('"');
+ }
+ for (uint32_t n = 0; n < length; ++n) {
+ uint8_t value = buf[n];
+
+ // Ignore trailing NUL characters
+ if (value == 0 && n + 1 == length) {
+ break;
+ }
+
+ if (value == '"' || value == '\\') {
+ putchar('\\');
+ putchar(value);
+ } else if (value >= 0x20 && value < 0x7f) {
+ putchar(value);
+ } else {
+ printf("\\x%02x", value);
+ }
+ }
+ if (add_quotes) {
+ putchar('"');
+ }
+}
+
+void lldp_print_mac(const uint8_t* buf, uint32_t length) {
+ if (length != 6) {
+ fputs("<bad_mac:", stdout);
+ lldp_print_value(buf, length);
+ putchar('>');
+ return;
+ }
+
+ printf("%02x:%02x:%02x:%02x:%02x:%02x",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+void lldp_print_net_addr(const uint8_t* buf, uint32_t length) {
+ if (length < 1) {
+ return;
+ }
+
+ if (buf[0] == 1 && length == 5) {
+ // IPv4
+ struct in_addr addr;
+ memcpy(&addr.s_addr, buf + 1, length - 1);
+
+ char str[INET_ADDRSTRLEN];
+ if (inet_ntop(AF_INET, &addr, str, sizeof(str)) != NULL) {
+ fputs(str, stdout);
+ return;
+ }
+ } else if (buf[0] == 2 && length == 17) {
+ struct in6_addr addr;
+ memcpy(&addr.s6_addr, buf + 1, length - 1);
+
+ char str[INET6_ADDRSTRLEN];
+ if (inet_ntop(AF_INET6, &addr, str, sizeof(str)) != NULL) {
+ fputs(str, stdout);
+ return;
+ }
+ }
+
+ // If we are still here, this wasn't IPv4 or IPv6, or we failed to parse it.
+ printf("<net_addr:%d:", buf[0]);
+ lldp_print_value(buf + 1, length - 1);
+ putchar('>');
+}
+
+void lldp_print_neighbor(lldp_neighbor_t* neighbor) {
+ fprintf(stdout, "%s: local_port=%s",
+ neighbor->protocol, neighbor->local_interface);
+ fputs(" remote_system=", stdout);
+ if (neighbor->system_name) {
+ lldp_print_value(neighbor->system_name, neighbor->system_name_length);
+ } else if (neighbor->chassis_id_type == LLDP_CHASSIS_MAC_ADDRESS) {
+ lldp_print_mac(neighbor->chassis_id, neighbor->chassis_id_length);
+ } else if (neighbor->chassis_id_type == LLDP_CHASSIS_NET_ADDRESS) {
+ lldp_print_net_addr(neighbor->chassis_id, neighbor->chassis_id_length);
+ } else {
+ lldp_print_value(neighbor->chassis_id, neighbor->chassis_id_length);
+ }
+
+ fputs(" remote_port=", stdout);
+ if (neighbor->port_id_type == LLDP_PORT_MAC_ADDRESS) {
+ lldp_print_mac(neighbor->port_id, neighbor->port_id_length);
+ } else if (neighbor->port_id_type == LLDP_PORT_NET_ADDRESS) {
+ lldp_print_net_addr(neighbor->port_id, neighbor->port_id_length);
+ } else {
+ lldp_print_value(neighbor->port_id, neighbor->port_id_length);
+ }
+ putchar('\n');
+}
+
+uint16_t lldp_read_u16(const uint8_t** buf) {
+ // Use memcpy() to comply with strict-aliasing rules.
+ // The compiler will optimize this away anyway.
+ uint16_t result;
+ memcpy(&result, *buf, 2);
+ (*buf) += 2;
+ return htons(result);
+}
+
+int lldp_parse_lldp(lldp_neighbor_t* neighbor,
+ const uint8_t* buf,
+ const uint8_t* end) {
+ while (buf < end) {
+ // Parse the type (7 bits) and length (9 bits)
+ if ((end - buf) < 2) {
+ errmsg("LLDPDU truncated in tag/length header");
+ return -EINVAL;
+ }
+ uint16_t length = lldp_read_u16(&buf);
+ uint16_t type = (length >> 9);
+ length &= 0x01ff;
+
+ if ((end - buf) < length) {
+ errmsg("LLDPDU truncated inside field of type %d: "
+ "field_length=%d, remaining=%d", type, length, end - buf);
+ return -EINVAL;
+ }
+
+ if (type == LLDP_TYPE_CHASSIS_ID) {
+ if (length < 1) {
+ errmsg("LLDPDU with invalid chassis ID length %d", length);
+ return -EINVAL;
+ }
+ neighbor->chassis_id_type = buf[0];
+ neighbor->chassis_id = buf + 1;
+ neighbor->chassis_id_length = length - 1;
+ } else if (type == LLDP_TYPE_PORT_ID) {
+ if (length < 1) {
+ errmsg("LLDPDU with invalid port ID length %d", length);
+ return -EINVAL;
+ }
+ neighbor->port_id_type = buf[0];
+ neighbor->port_id = buf + 1;
+ neighbor->port_id_length = length - 1;
+ } else if (type == LLDP_TYPE_SYSTEM_NAME) {
+ neighbor->system_name = buf;
+ neighbor->system_name_length = length;
+ }
+
+ buf += length;
+
+ if (type == LLDP_TYPE_END) {
+ break;
+ }
+ }
+
+ if (!neighbor->chassis_id) {
+ errmsg("received LLDPDU with missing chassis ID");
+ return -EINVAL;
+ }
+ if (!neighbor->port_id) {
+ errmsg("received LLDPDU with missing port ID");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int lldp_parse_cdp(lldp_neighbor_t* neighbor,
+ const uint8_t* buf,
+ const uint8_t* end) {
+ // Skip over some initial headers:
+ // 1 byte DSAP
+ // 1 byte SSAP
+ // 1 byte LLC control field
+ // 3 byte SNAP vendor code
+ // 2 byte SNAP local code
+ // 1 byte CDP version
+ // 1 byte TTL
+ // 2 byte checksum
+ if ((end - buf) < 12) {
+ errmsg("CDP PDU truncated in initial headers: length=%d", end - buf);
+ return -EINVAL;
+ }
+ buf += 8;
+ uint8_t cdp_version = *buf;
+ if (cdp_version != 2) {
+ // We only support CDP version 2 for now.
+ debugmsg("ignoring unsupported CDP PDU with version %d", cdp_version);
+ return -EPFNOSUPPORT;
+ }
+ buf += 4;
+
+ while (buf < end) {
+ if ((end - buf) < 4) {
+ errmsg("CDP PDU truncated in tag/length header");
+ return -EINVAL;
+ }
+ uint16_t type = lldp_read_u16(&buf);
+ uint16_t length = lldp_read_u16(&buf);
+
+ if (length < 4) {
+ errmsg("CDP PDU with bad length=%d for field of type %d",
+ length, type);
+ return -EINVAL;
+ }
+ length -= 4;
+ if ((end - buf) < length) {
+ errmsg("CDP PDU truncated inside field of type %d: "
+ "field_length=%d, remaining=%d", type, length, end - buf);
+ return -EINVAL;
+ }
+
+ if (type == CDP_TYPE_DEVICE_ID) {
+ neighbor->chassis_id_type = LLDP_CHASSIS_CDP;
+ neighbor->chassis_id = buf;
+ neighbor->chassis_id_length = length;
+ } else if (type == CDP_TYPE_PORT_ID) {
+ neighbor->port_id_type = LLDP_PORT_CDP;
+ neighbor->port_id = buf;
+ neighbor->port_id_length = length;
+ } else if (type == CDP_TYPE_SYSTEM_NAME) {
+ neighbor->system_name = buf;
+ neighbor->system_name_length = length;
+ }
+ buf += length;
+ }
+
+ if (!neighbor->chassis_id) {
+ errmsg("received CDP PDU with missing device ID");
+ return -EINVAL;
+ }
+ if (!neighbor->port_id) {
+ errmsg("received CDP PDU with missing port ID");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int lldp_process_packet(const uint8_t* buf,
+ size_t length,
+ const char* interface,
+ bool process_cdp,
+ bool* processed) {
+ int returnCode = -EINVAL;
+ *processed = false;
+
+ {
+ // Bail if the minimum ethernet frame size is not met
+ if (length < MIN_FRAME_LENGTH) {
+ errmsg("received too-short frame on interface %s: length=%d",
+ interface, length);
+ returnCode = -EINVAL;
+ goto error;
+ }
+
+ const uint8_t* buf_start = buf;
+ const uint8_t* end = buf + length;
+
+ const uint8_t* dest_mac = buf;
+ buf += 6;
+ const uint8_t* src_mac = buf;
+ buf += 6;
+ uint16_t ethertype = lldp_read_u16(&buf);
+
+ if (ethertype == ETHERTYPE_VLAN) {
+ uint16_t vlan = lldp_read_u16(&buf);
+ ethertype = lldp_read_u16(&buf);
+ }
+
+ if (ethertype == ETHERTYPE_LLDP) {
+ lldp_neighbor_t neighbor;
+ lldp_neighbor_init(&neighbor, "LLDP", interface, src_mac);
+ returnCode = lldp_parse_lldp(&neighbor, buf, end);
+ if (returnCode != 0) {
+ goto error;
+ }
+ lldp_print_neighbor(&neighbor);
+ fflush(stdout);
+ *processed = true;
+ } else if ((memcmp(dest_mac, MAC_CDP, 6) == 0) && (ethertype < 0x600)) {
+ if (process_cdp) {
+ lldp_neighbor_t neighbor;
+ lldp_neighbor_init(&neighbor, "CDP", interface, src_mac);
+ returnCode = lldp_parse_cdp(&neighbor, buf, end);
+ if (returnCode != 0) {
+ goto error;
+ }
+ lldp_print_neighbor(&neighbor);
+ fflush(stdout);
+ *processed = true;
+ } else if (cdp_sav_data.num_sav_cdp < cdp_sav_data.max_sav_cdp) {
+ cdp_sav_data.frame[cdp_sav_data.num_sav_cdp].cdp_buf = malloc(length);
+ assert(cdp_sav_data.frame[cdp_sav_data.num_sav_cdp].cdp_buf);
+ memcpy(cdp_sav_data.frame[cdp_sav_data.num_sav_cdp].cdp_buf, buf_start,
+ length);
+ cdp_sav_data.frame[cdp_sav_data.num_sav_cdp].length = length;
+ cdp_sav_data.num_sav_cdp++;
+ }
+ } else {
+ // Some other packet type that we don't care about.
+ debugmsg("Ignored packet on %s: ethertype=0x%04x",
+ interface, ethertype);
+ }
+
+ returnCode = 0;
+ goto cleanup;
+ }
+
+error:
+ assert(returnCode < 0);
+cleanup:
+ return returnCode;
+}
+
+int lldp_receive(int fd, const char* interface, bool cdp, bool* processed) {
+ int returnCode = -EINVAL;
+ *processed = false;
+ {
+ uint8_t buf[MAX_FRAME_LENGTH];
+
+ struct sockaddr_ll src_addr;
+ socklen_t addr_len;
+ ssize_t len = recvfrom(fd, buf, MAX_FRAME_LENGTH, 0,
+ (struct sockaddr*)&src_addr, &addr_len);
+ if (len == -1) {
+ if (errno != EINTR) {
+ errmsg("error reading packet from %s", interface);
+ }
+ returnCode = -errno;
+ goto error;
+ }
+
+ returnCode = lldp_process_packet(buf, len, interface, cdp, processed);
+ goto cleanup;
+ }
+
+error:
+ assert(returnCode < 0);
+cleanup:
+ return returnCode;
+}
+
+void exit_handler(int signum) {
+ g_interrupt = true;
+}
+
+void usage_short(FILE* out) {
+ fprintf(out, "lldp-util [-h] [-c] [-i <interface>] "
+ "[-n <count>] [-t <timeout>]\n");
+}
+
+void usage_full(FILE* out) {
+ usage_short(out);
+ fprintf(out,
+ "\n"
+ " -c Report CDP packets as they arrive in addition "
+ "to LLDP\n"
+ " -h Show this help message and exit\n"
+ " -i <interface> Specify the interface to listen on\n"
+ " -n <count> Exit after receiving <count> LLDP packets\n"
+ " -t <timeout> Exit after <timeout> seconds\n"
+ " Negative or 0 means no timeout\n"
+ "\n"
+ "If neither -n nor -t are specified, lldp-util uses a 65 second\n"
+ "timeout by default\n"
+ );
+}
+
+int main(int argc, char* argv[]) {
+ const char* interface = "eth0";
+ long timeout = 0;
+ bool has_timeout = false;
+ long max_count = 0;
+ bool has_max_count = false;
+ bool inline_cdp = false;
+
+ while (true) {
+ int opt = getopt(argc, argv, "chi:n:t:");
+ if (opt == -1) {
+ break;
+ }
+ switch (opt) {
+ case 'c':
+ inline_cdp = true;
+ break;
+ case 'h':
+ usage_full(stdout);
+ return 0;
+ case 'i':
+ interface = optarg;
+ break;
+ case 'n': {
+ char* end;
+ max_count = strtol(optarg, &end, 10);
+ if (end == optarg || *end != '\0') {
+ fprintf(stderr, "error: bad count value: must be an integer\n");
+ return 1;
+ }
+ has_max_count = true;
+ break;
+ }
+ case 't': {
+ char* end;
+ timeout = strtol(optarg, &end, 10);
+ if (end == optarg || *end != '\0') {
+ fprintf(stderr, "error: bad timeout value: must be an integer\n");
+ return 1;
+ }
+ has_timeout = true;
+ break;
+ }
+ default:
+ usage_short(stderr);
+ return 1;
+ }
+ }
+
+ // Default to a 65 second timeout if no other limits were specified.
+ if (!has_max_count && !has_timeout) {
+ timeout = 65;
+ }
+
+ int fd = lldp_open(interface);
+ if (fd < 0) {
+ return 1;
+ }
+
+ struct sigaction sa;
+
+ // Clear all fields in sa. In particular, SA_RESTART must not be set in
+ // sa_flags field because we want recvfrom to be interrupted.
+ memset(&sa, 0, sizeof(sa));
+
+ sa.sa_handler = exit_handler;
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ // Automatically stop after 65 seconds
+ if (timeout > 0) {
+ sigaction(SIGALRM, &sa, NULL);
+ alarm(timeout);
+ }
+
+ // In the case when we are asked not to report CDP packets as they arrive,
+ // we will save them in a global buffer. On exiting, if we have not seen
+ // any LLDP packets, we'll dump the CDP packets that arrived.
+ if (!inline_cdp) {
+ if (max_count > 0) {
+ cdp_sav_data.max_sav_cdp = max_count;
+ } else {
+ cdp_sav_data.max_sav_cdp = DFLT_MAX_SAV_CDP;
+ }
+ cdp_sav_data.frame = malloc(sizeof(cdp_frame_t) *
+ cdp_sav_data.max_sav_cdp);
+ if (cdp_sav_data.frame == NULL) {
+ printf("memory allocation failed for saved frames\n");
+ exit(1);
+ }
+ }
+
+ printf("Listening for LLDP packets...\n");
+ fflush(stdout);
+ long count = 0;
+ bool processed;
+ while (true) {
+ lldp_receive(fd, interface, inline_cdp, &processed);
+ if (processed) {
+ ++count;
+ if (max_count > 0 && count >= max_count) {
+ break;
+ }
+ }
+ if (g_interrupt) {
+ break;
+ }
+ }
+
+ // Print saved CDP packets if we haven't printed anything yet
+ if (count == 0) {
+ for (int i = 0; i < cdp_sav_data.num_sav_cdp; i++) {
+ lldp_process_packet(cdp_sav_data.frame[i].cdp_buf,
+ cdp_sav_data.frame[i].length,
+ interface, true, &processed);
+ }
+ }
+
+ return 0;
+}
diff --git a/common/recipes-connectivity/lldp-util/lldp-util_0.1.bb b/common/recipes-connectivity/lldp-util/lldp-util_0.1.bb
new file mode 100644
index 0000000..eb53e9a
--- /dev/null
+++ b/common/recipes-connectivity/lldp-util/lldp-util_0.1.bb
@@ -0,0 +1,21 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+
+SUMMARY = "LLDP Utility"
+DESCRIPTION = "A utility for reporting LLDP information"
+SECTION = "base"
+PR = "r1"
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=cc7ed73f378cc0ea228aebab24237853 \
+ file://PATENTS;md5=aed2575e5dba9ba3aea25cfeddb8f1d2 "
+
+SRC_URI = "file://src \
+ "
+
+S = "${WORKDIR}/src"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 755 lldp-util ${D}${bindir}
+}
+
+FILES_${PN} = " ${bindir} "
diff --git a/common/recipes-core/base-files/base-files_%.bbappend b/common/recipes-core/base-files/base-files_%.bbappend
index 340ad2c..6a73f2b 100644
--- a/common/recipes-core/base-files/base-files_%.bbappend
+++ b/common/recipes-core/base-files/base-files_%.bbappend
@@ -15,8 +15,8 @@ do_install_bmc_issue () {
dir=$(dirname $dir)
done
- if [ -d "$dir/meta-aspeed/.git" ]; then
- srcdir="$dir/meta-aspeed"
+ if [ -d "$dir/meta-openbmc/.git" ]; then
+ srcdir="$dir/meta-openbmc"
srcdir_git="${srcdir}/.git"
version=$(git --git-dir=${srcdir_git} --work-tree=${srcdir} describe --dirty 2> /dev/null)
else
diff --git a/common/recipes-core/cfg-util/cfg-util_0.1.bb b/common/recipes-core/cfg-util/cfg-util_0.1.bb
new file mode 100644
index 0000000..13b6568
--- /dev/null
+++ b/common/recipes-core/cfg-util/cfg-util_0.1.bb
@@ -0,0 +1,36 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "Configuration Utility"
+DESCRIPTION = "Utility for reading or writing configuration"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://cfg-util.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238"
+
+SRC_URI = "file://Makefile \
+ file://cfg-util.c \
+ "
+S = "${WORKDIR}"
+
+LDFLAGS =+ " -lpal "
+
+DEPENDS =+ " libpal "
+
+binfiles = "cfg-util"
+
+pkgdir = "cfg-util"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ install -m 755 cfg-util ${dst}/cfg-util
+ ln -snf ../fbpackages/${pkgdir}/cfg-util ${bin}/cfg-util
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/cfg-util ${prefix}/local/bin"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/cfg-util/files/Makefile b/common/recipes-core/cfg-util/files/Makefile
new file mode 100644
index 0000000..05b9b16
--- /dev/null
+++ b/common/recipes-core/cfg-util/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: cfg-util
+
+
+cfg-util: cfg-util.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o cfg-util
diff --git a/common/recipes-core/cfg-util/files/cfg-util.c b/common/recipes-core/cfg-util/files/cfg-util.c
new file mode 100644
index 0000000..99618f7
--- /dev/null
+++ b/common/recipes-core/cfg-util/files/cfg-util.c
@@ -0,0 +1,78 @@
+/*
+ * cfg-util
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <openbmc/pal.h>
+
+static void
+print_usage(void) {
+ printf("Usage: cfg-util <dump-all|key> <value>\n");
+}
+
+int
+main(int argc, char **argv) {
+
+ int ret;
+ uint8_t key[MAX_KEY_LEN] = {0};
+ uint8_t val[MAX_VALUE_LEN] = {0};
+
+ // Handle boundary checks
+ if (argc < 2 || argc > 3) {
+ goto err_exit;
+ }
+
+ // Handle dump of key value data base
+ if ((argc == 2) && (!strcmp(argv[1], "dump-all"))){
+ pal_dump_key_value();
+ return 0;
+ }
+
+ // Handle Get the Configuration
+ if (argc == 2) {
+ snprintf(key, MAX_KEY_LEN, "%s", argv[1]);
+
+ ret = pal_get_key_value(key, val);
+ if (ret) {
+ goto err_exit;
+ }
+
+ printf("%s\n", val);
+ return 0;
+ }
+
+ // Handle Set the configuration
+ snprintf(key, MAX_KEY_LEN, "%s", argv[1]);
+ snprintf(val, MAX_VALUE_LEN, "%s", argv[2]);
+
+ ret = pal_set_key_value(key, val);
+ if (ret) {
+ goto err_exit;
+ }
+
+ return 0;
+
+err_exit:
+ print_usage();
+ exit(-1);
+}
diff --git a/common/recipes-core/consoled/consoled_0.1.bb b/common/recipes-core/consoled/consoled_0.1.bb
new file mode 100644
index 0000000..5b6edd1
--- /dev/null
+++ b/common/recipes-core/consoled/consoled_0.1.bb
@@ -0,0 +1,36 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "Serial Buffer"
+DESCRIPTION = "Daemon for serial buffering"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://consoled.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238"
+
+SRC_URI = "file://Makefile \
+ file://consoled.c \
+ "
+S = "${WORKDIR}"
+
+LDFLAGS =+ " -lpal "
+
+DEPENDS =+ " libpal "
+
+binfiles = "consoled"
+
+pkgdir = "consoled"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ install -m 755 consoled ${dst}/consoled
+ ln -snf ../fbpackages/${pkgdir}/consoled ${bin}/consoled
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/consoled ${prefix}/local/bin"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/consoled/files/Makefile b/common/recipes-core/consoled/files/Makefile
new file mode 100644
index 0000000..2b30ef2
--- /dev/null
+++ b/common/recipes-core/consoled/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: consoled
+
+
+consoled: consoled.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o consoled
diff --git a/common/recipes-core/consoled/files/consoled.c b/common/recipes-core/consoled/files/consoled.c
new file mode 100644
index 0000000..9f17e31
--- /dev/null
+++ b/common/recipes-core/consoled/files/consoled.c
@@ -0,0 +1,284 @@
+/*
+ * consoled
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <termios.h>
+#include <signal.h>
+#include <openbmc/pal.h>
+
+#define BAUDRATE B57600
+#define CTRL_X 0x18
+#define ASCII_ENTER 0x0D
+
+static sig_atomic_t sigexit = 0;
+
+static void
+write_data(int file, char *buf, int len, char *fname) {
+ int wlen = 0;
+ char *tbuf = buf;
+ while(len > 0) {
+ errno = 0;
+ wlen = write(file, tbuf, len);
+ // In case wlen < 0, retry write()
+ if (wlen >= 0) {
+ len -= wlen;
+ tbuf = tbuf + wlen;
+ } else {
+ syslog(LOG_ALERT, "write_data: write() failed to file %s | errno: %d",
+ fname, errno);
+ return;
+ }
+ }
+}
+
+static void
+exit_session(int sig)
+{
+ sigexit = sig;
+}
+
+static void
+print_usage() {
+ printf("Usage: consoled [ %s ]\n", pal_server_list);
+}
+
+static void
+run_console(char* fru_name, int term) {
+
+ int i;
+ int tty; // serial port
+ int buf_fd; // Buffer File
+ int blen; // len for
+ int nfd = 0; // For number of fd
+ int nevents; // For number of events in fd
+ int nline = 0;
+ //int pid_fd;
+ int flags;
+ pid_t pid; // For pid of the daemon
+ uint8_t fru;
+ char in; // For stdin character
+ char data[32];
+ char pid_file[64];
+ char devtty[32]; // For tty dev path
+ char bfname[32]; // For buffer file path
+ char old_bfname[32]; // For old buffer file path
+ char buf[256]; // For buffer data
+ struct termios ottytio, nttytio; // For the tty dev
+
+ int stdi; // STDIN_FILENO
+ int stdo; // STDOUT_FILENO
+ struct termios ostditio, nstditio; // For STDIN_FILENO
+ struct termios ostdotio, nstdotio; // For STDOUT_FILENO
+
+ struct pollfd pfd[2];
+
+ /* Start Daemon for the console buffering */
+ if (!term) {
+ daemon(0,1);
+ openlog("consoled", LOG_CONS, LOG_DAEMON);
+ syslog(LOG_INFO, "consoled: daemon started");
+ }
+
+ if (pal_get_fru_id(fru_name, &fru)) {
+ exit(-1);
+ }
+
+ if (pal_get_fru_devtty(fru, devtty)) {
+ exit(-1);
+ }
+
+ /* Handling the few Signals differently */
+ signal(SIGHUP, exit_session);
+ signal(SIGINT, exit_session);
+ signal(SIGTERM, exit_session);
+ signal(SIGPIPE, exit_session);
+ signal(SIGQUIT, exit_session);
+
+ /* Different flag value for tty dev */
+ flags = term == 1 ? (O_RDWR | O_NOCTTY | O_NONBLOCK) :
+ (O_RDONLY | O_NOCTTY | O_NONBLOCK);
+
+ if ((tty = open(devtty, flags)) < 0) {
+ syslog(LOG_ALERT, "Cannot open the file %s", devtty);
+ exit(-1);
+ }
+ fcntl(tty, F_SETFL, O_RDWR);
+
+ /* Changing the attributes of the tty dev */
+ tcgetattr(tty, &ottytio);
+ memcpy(&nttytio, &ottytio, sizeof(struct termios));
+ cfmakeraw(&nttytio);
+ cfsetspeed(&nttytio, BAUDRATE);
+ tcflush(tty, TCIFLUSH);
+ tcsetattr(tty, TCSANOW, &nttytio);
+ pfd[0].fd = tty;
+ pfd[0].events = POLLIN;
+ nfd++;
+
+ /* Buffering the console data into a file */
+ sprintf(old_bfname, "/tmp/consoled_%s_log-old", fru_name);
+ sprintf(bfname, "/tmp/consoled_%s_log", fru_name);
+ if ((buf_fd = open(bfname, O_RDWR | O_APPEND | O_CREAT, 0666)) < 0) {
+ syslog(LOG_ALERT, "Cannot open the file %s", bfname);
+ exit(-1);
+ }
+
+ if (term) {
+ /* Changing the attributes of STDIN_FILENO */
+ stdi = STDIN_FILENO;
+ tcgetattr(stdi, &ostditio);
+ memcpy(&nstditio, &ostditio, sizeof(struct termios));
+ cfmakeraw(&nstditio);
+ tcflush(stdi, TCIFLUSH);
+ tcsetattr(stdi, TCSANOW, &nstditio);
+
+ /* Changing the attributes of STDOUT_FILENO */
+ stdo = STDOUT_FILENO;
+ tcgetattr(stdo, &ostdotio);
+ memcpy(&nstdotio, &ostdotio, sizeof(struct termios));
+ cfmakeraw(&nstdotio);
+ tcflush(stdo, TCIFLUSH);
+ tcsetattr(stdo, TCSANOW, &nstdotio);
+
+ /* Adding STDIN_FILENO to the poll fd set */
+ pfd[1].fd = stdi;
+ pfd[1].events = POLLIN;
+ nfd++;
+ }
+
+ /* Handling the input event from the terminal and tty dev */
+ while (!sigexit && (nevents = poll(pfd, nfd, -1 /* Timeout */))) {
+
+ /* Input to the terminal from the user */
+ if (term && nevents && nfd > 1 && pfd[1].revents > 0) {
+ blen = read(stdi, &in, sizeof(in));
+ if (blen < 1) {
+ nfd--;
+ }
+
+ if (in == CTRL_X) {
+ break;
+ }
+
+ write_data(tty, &in, sizeof(in), "tty");
+
+ nevents--;
+ }
+
+ /* Input from the tty dev */
+ if (nevents && pfd[0].revents > 0) {
+ blen = read(tty, buf, sizeof(buf));
+ if (blen > 0) {
+ for (i = 0; i < blen; i++) {
+ if (buf[i] == 0xD)
+ nline++;
+ }
+ write_data(buf_fd, buf, blen, bfname);
+ fsync(buf_fd);
+ if (term) {
+ write_data(stdo, buf, blen, "STDOUT_FILENO");
+ }
+ } else if (blen < 0) {
+ raise(SIGHUP);
+ }
+
+ /* Log Rotation */
+ if (nline >= 300) {
+ close(buf_fd);
+ remove(old_bfname);
+ rename(bfname, old_bfname);
+ if ((buf_fd = open(bfname, O_RDWR | O_APPEND | O_CREAT, 0666)) < 0) {
+ syslog(LOG_ALERT, "Cannot open the file %s", bfname);
+ exit(-1);
+ }
+ nline = 0;
+ }
+ nevents--;
+ }
+ }
+
+ /* Close the console buffer file */
+ close(buf_fd);
+
+ /* Revert the tty dev to old attributes */
+ tcflush(tty, TCIFLUSH);
+ tcsetattr(tty, TCSANOW, &ottytio);
+
+ /* Revert STDIN to old attributes */
+ if (term) {
+ tcflush(stdo, TCIFLUSH);
+ tcsetattr(stdo, TCSANOW, &ostdotio);
+ tcflush(stdi, TCIFLUSH);
+ tcsetattr(stdi, TCSANOW, &ostditio);
+ }
+
+ /* Delete the pid file */
+ if (!term)
+ remove(pid_file);
+}
+
+int
+main(int argc, void **argv) {
+ int dev, rc, lock_file;
+ char file[64];
+ int term;
+ char *fru_name;
+
+ if (argc != 3) {
+ print_usage();
+ exit(1);
+ }
+
+ // A lock file for one instance of consoled for each fru
+ sprintf(file, "/var/lock/consoled_%s", argv[1]);
+ lock_file = open(file, O_CREAT | O_RDWR, 0666);
+ rc = flock(lock_file, LOCK_EX | LOCK_NB);
+ if(rc) {
+ if(errno == EWOULDBLOCK) {
+ printf("Another consoled %s instance is running...\n", argv[1]);
+ exit(-1);
+ }
+ } else {
+
+ fru_name = argv[1];
+
+ if (!strcmp(argv[2], "--buffer")) {
+ term = 0;
+ } else if (!strcmp(argv[2], "--term")) {
+ term = 1;
+ } else {
+ print_usage();
+ exit(-1);
+ }
+
+ run_console(fru_name, term);
+ }
+
+ return sigexit;
+}
+
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/Makefile b/common/recipes-core/fan-ctrl/fan-ctrl/Makefile
new file mode 100644
index 0000000..da74a34
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+all: fand
+
+fand: fand.cpp watchdog.cpp
+ $(CXX) $(CXXFLAGS) -pthread -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o fand
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/README b/common/recipes-core/fan-ctrl/fan-ctrl/README
new file mode 100644
index 0000000..2a92b9d
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/README
@@ -0,0 +1,5 @@
+The AST PWM/Tach driver is in the kernel sources at drivers/hwmon/ast_pwm_fan.c
+
+There are 7 PWM output pins. Each PWM can be configured in one of 3 types (M,
+N, or O). The clock settings for each type are configurable. See init_pwm.sh
+for more comments about how we configure the settings.
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp
new file mode 100644
index 0000000..49c6f6b
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp
@@ -0,0 +1,1030 @@
+/*
+ * fand
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Daemon to manage the fan speed to ensure that we stay within a reasonable
+ * temperature range. We're using a simplistic algorithm to get started:
+ *
+ * If the fan is already on high, we'll move it to medium if we fall below
+ * a top temperature. If we're on medium, we'll move it to high
+ * if the temperature goes over the top value, and to low if the
+ * temperature falls to a bottom level. If the fan is on low,
+ * we'll increase the speed if the temperature rises to the top level.
+ *
+ * To ensure that we're not just turning the fans up, then back down again,
+ * we'll require an extra few degrees of temperature drop before we lower
+ * the fan speed.
+ *
+ * We check the RPM of the fans against the requested RPMs to determine
+ * whether the fans are failing, in which case we'll turn up all of
+ * the other fans and report the problem..
+ *
+ * TODO: Implement a PID algorithm to closely track the ideal temperature.
+ * TODO: Determine if the daemon is already started.
+ */
+
+/* Yeah, the file ends in .cpp, but it's a C program. Deal. */
+
+#if !defined(CONFIG_YOSEMITE) && !defined(CONFIG_WEDGE)
+#error "No hardware platform defined!"
+#endif
+#if defined(CONFIG_YOSEMITE) && defined(CONFIG_WEDGE)
+#error "Both hardware platform defined!"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <syslog.h>
+#ifdef CONFIG_YOSEMITE
+#include <openbmc/ipmi.h>
+#include <facebook/bic.h>
+#include <facebook/yosemite_sensor.h>
+#endif
+#ifdef CONFIG_WEDGE
+#include <facebook/wedge_eeprom.h>
+#endif
+
+#include "watchdog.h"
+
+/* Sensor definitions */
+
+#ifdef CONFIG_WEDGE
+#define INTERNAL_TEMPS(x) ((x) * 1000) // stored a C * 1000
+#define EXTERNAL_TEMPS(x) ((x) / 1000)
+#elif CONFIG_YOSEMITE
+#define INTERNAL_TEMPS(x) (x)
+#define EXTERNAL_TEMPS(x) (x)
+#define TOTAL_1S_SERVERS 4
+#endif
+
+#define I2C_BUS_3_DIR "/sys/class/i2c-adapter/i2c-3/"
+#define I2C_BUS_4_DIR "/sys/class/i2c-adapter/i2c-4/"
+
+#define INTAKE_TEMP_DEVICE I2C_BUS_3_DIR "3-0048"
+#define T2_TEMP_DEVICE I2C_BUS_3_DIR "3-0049"
+#define EXHAUST_TEMP_DEVICE I2C_BUS_3_DIR "3-004a"
+#define USERVER_TEMP_DEVICE I2C_BUS_4_DIR "4-0040"
+
+/*
+ * The sensor for the uServer CPU is not on the CPU itself, so it reads
+ * a little low. We are special casing this, but we should obviously
+ * be thinking about a way to generalize these tweaks, and perhaps
+ * the entire configuration. JSON file?
+ */
+
+#ifdef CONFIG_WEDGE
+#define USERVER_TEMP_FUDGE INTERNAL_TEMPS(10)
+#else
+#define USERVER_TEMP_FUDGE INTERNAL_TEMPS(1)
+#endif
+
+#define BAD_TEMP INTERNAL_TEMPS(-60)
+
+#define BAD_READ_THRESHOLD 4 /* How many times can reads fail */
+#define FAN_FAILURE_THRESHOLD 4 /* How many times can a fan fail */
+#define FAN_SHUTDOWN_THRESHOLD 20 /* How long fans can be failed before */
+ /* we just shut down the whole thing. */
+
+
+#define PWM_DIR "/sys/devices/platform/ast_pwm_tacho.0"
+
+#define PWM_UNIT_MAX 96
+
+#define LARGEST_DEVICE_NAME 120
+
+#define GPIO_USERVER_POWER_DIRECTION "/sys/class/gpio/gpio25/direction"
+#define GPIO_USERVER_POWER "/sys/class/gpio/gpio25/value"
+#define GPIO_T2_POWER_DIRECTION "/tmp/gpionames/T2_POWER_UP/direction"
+#define GPIO_T2_POWER "/tmp/gpionames/T2_POWER_UP/value"
+
+#define GPIO_FAN0_LED "/sys/class/gpio/gpio53/value"
+#define GPIO_FAN1_LED "/sys/class/gpio/gpio54/value"
+#define GPIO_FAN2_LED "/sys/class/gpio/gpio55/value"
+#define GPIO_FAN3_LED "/sys/class/gpio/gpio72/value"
+
+const char *fan_led[] = {GPIO_FAN0_LED, GPIO_FAN1_LED,
+ GPIO_FAN2_LED, GPIO_FAN3_LED};
+
+#define FAN_LED_RED "0"
+#define FAN_LED_BLUE "1"
+
+#define GPIO_PIN_ID "/sys/class/gpio/gpio%d/value"
+#define REV_IDS 3
+#define GPIO_REV_ID_START 192
+
+#define BOARD_IDS 4
+#define GPIO_BOARD_ID_START 160
+
+/*
+ * With hardware revisions after 3, we use a different set of pins for
+ * the BOARD_ID.
+ */
+
+#define REV_ID_NEW_BOARD_ID 3
+#define GPIO_BOARD_ID_START_NEW 166
+
+#define REPORT_TEMP 720 /* Report temp every so many cycles */
+
+/* Sensor limits and tuning parameters */
+
+#define INTAKE_LIMIT INTERNAL_TEMPS(60)
+#define T2_LIMIT INTERNAL_TEMPS(80)
+#define USERVER_LIMIT INTERNAL_TEMPS(90)
+
+#define TEMP_TOP INTERNAL_TEMPS(70)
+#define TEMP_BOTTOM INTERNAL_TEMPS(40)
+
+/*
+ * Toggling the fan constantly will wear it out (and annoy anyone who
+ * can hear it), so we'll only turn down the fan after the temperature
+ * has dipped a bit below the point at which we'd otherwise switch
+ * things up.
+ */
+
+#define COOLDOWN_SLOP INTERNAL_TEMPS(6)
+
+#define WEDGE_FAN_LOW 35
+#define WEDGE_FAN_MEDIUM 50
+#define WEDGE_FAN_HIGH 70
+#define WEDGE_FAN_MAX 99
+
+#define SIXPACK_FAN_LOW 35
+#define SIXPACK_FAN_MEDIUM 55
+#define SIXPACK_FAN_HIGH 75
+#define SIXPACK_FAN_MAX 99
+
+/*
+ * Mapping physical to hardware addresses for fans; it's different for
+ * RPM measuring and PWM setting, naturally. Doh.
+ */
+
+#ifdef CONFIG_WEDGE
+int fan_to_rpm_map[] = {3, 2, 0, 1};
+int fan_to_pwm_map[] = {7, 6, 0, 1};
+#define FANS 4
+// Tacho offset between front and rear fans:
+#define REAR_FAN_OFFSET 4
+#define BACK_TO_BACK_FANS
+#else
+int fan_to_rpm_map[] = {0, 1};
+int fan_to_pwm_map[] = {0, 1};
+#define FANS 2
+// Tacho offset between front and rear fans:
+#define REAR_FAN_OFFSET 1
+#endif
+
+
+/*
+ * The measured RPM of the fans doesn't match linearly to the requested
+ * rate. In addition, there are coaxially mounted fans, so the rear fans
+ * feed into the front fans. The rear fans will run slower since they're
+ * grabbing still air, and the front fants are getting an extra boost.
+ *
+ * We'd like to measure the fan RPM and compare it to the expected RPM
+ * so that we can detect failed fans, so we have a table (derived from
+ * hardware testing):
+ */
+
+struct rpm_to_pct_map {
+ ushort pct;
+ ushort rpm;
+};
+
+#ifdef CONFIG_WEDGE
+struct rpm_to_pct_map rpm_front_map[] = {{30, 6150},
+ {35, 7208},
+ {40, 8195},
+ {45, 9133},
+ {50, 10017},
+ {55, 10847},
+ {60, 11612},
+ {65, 12342},
+ {70, 13057},
+ {75, 13717},
+ {80, 14305},
+ {85, 14869},
+ {90, 15384},
+ {95, 15871},
+ {100, 16095}};
+#define FRONT_MAP_SIZE (sizeof(rpm_front_map) / sizeof(struct rpm_to_pct_map))
+
+struct rpm_to_pct_map rpm_rear_map[] = {{30, 3911},
+ {35, 4760},
+ {40, 5587},
+ {45, 6434},
+ {50, 7295},
+ {55, 8187},
+ {60, 9093},
+ {65, 10008},
+ {70, 10949},
+ {75, 11883},
+ {80, 12822},
+ {85, 13726},
+ {90, 14690},
+ {95, 15516},
+ {100, 15897}};
+#define REAR_MAP_SIZE (sizeof(rpm_rear_map) / sizeof(struct rpm_to_pct_map))
+#else
+struct rpm_to_pct_map rpm_map[] = {{30, 3413},
+ {35, 3859},
+ {40, 4305},
+ {45, 4686},
+ {50, 5032},
+ {55, 5432},
+ {60, 5991},
+ {65, 6460},
+ {70, 6927},
+ {75, 7379},
+ {80, 7733},
+ {85, 8156},
+ {90, 8599},
+ {95, 9049},
+ {100, 9265}};
+struct rpm_to_pct_map *rpm_front_map = rpm_map;
+struct rpm_to_pct_map *rpm_rear_map = rpm_map;
+#define MAP_SIZE (sizeof(rpm_map) / sizeof(struct rpm_to_pct_map))
+#define FRONT_MAP_SIZE MAP_SIZE
+#define REAR_MAP_SIZE MAP_SIZE
+
+#endif
+
+#define FAN_FAILURE_OFFSET 30
+
+int fan_low = WEDGE_FAN_LOW;
+int fan_medium = WEDGE_FAN_MEDIUM;
+int fan_high = WEDGE_FAN_HIGH;
+int fan_max = WEDGE_FAN_MAX;
+int total_fans = FANS;
+int fan_offset = 0;
+
+int temp_bottom = TEMP_BOTTOM;
+int temp_top = TEMP_TOP;
+
+int report_temp = REPORT_TEMP;
+bool verbose = false;
+
+void usage() {
+ fprintf(stderr,
+ "fand [-v] [-l <low-pct>] [-m <medium-pct>] "
+ "[-h <high-pct>]\n"
+ "\t[-b <temp-bottom>] [-t <temp-top>] [-r <report-temp>]\n\n"
+ "\tlow-pct defaults to %d%% fan\n"
+ "\tmedium-pct defaults to %d%% fan\n"
+ "\thigh-pct defaults to %d%% fan\n"
+ "\ttemp-bottom defaults to %dC\n"
+ "\ttemp-top defaults to %dC\n"
+ "\treport-temp defaults to every %d measurements\n\n"
+ "fand compensates for uServer temperature reading %d degrees low\n"
+ "kill with SIGUSR1 to stop watchdog\n",
+ fan_low,
+ fan_medium,
+ fan_high,
+ EXTERNAL_TEMPS(temp_bottom),
+ EXTERNAL_TEMPS(temp_top),
+ report_temp,
+ EXTERNAL_TEMPS(USERVER_TEMP_FUDGE));
+ exit(1);
+}
+
+/* We need to open the device each time to read a value */
+
+int read_device(const char *device, int *value) {
+ FILE *fp;
+ int rc;
+
+ fp = fopen(device, "r");
+ if (!fp) {
+ int err = errno;
+
+ syslog(LOG_INFO, "failed to open device %s", device);
+ return err;
+ }
+
+ rc = fscanf(fp, "%d", value);
+ fclose(fp);
+
+ if (rc != 1) {
+ syslog(LOG_INFO, "failed to read device %s", device);
+ return ENOENT;
+ } else {
+ return 0;
+ }
+}
+
+/* We need to open the device again each time to write a value */
+
+int write_device(const char *device, const char *value) {
+ FILE *fp;
+ int rc;
+
+ fp = fopen(device, "w");
+ if (!fp) {
+ int err = errno;
+
+ syslog(LOG_INFO, "failed to open device for write %s", device);
+ return err;
+ }
+
+ rc = fputs(value, fp);
+ fclose(fp);
+
+ if (rc < 0) {
+ syslog(LOG_INFO, "failed to write device %s", device);
+ return ENOENT;
+ } else {
+ return 0;
+ }
+}
+
+#ifdef CONFIG_WEDGE
+int read_temp(const char *device, int *value) {
+ char full_name[LARGEST_DEVICE_NAME + 1];
+
+ /* We set an impossible value to check for errors */
+ *value = BAD_TEMP;
+ snprintf(
+ full_name, LARGEST_DEVICE_NAME, "%s/temp1_input", device);
+ return read_device(full_name, value);
+}
+
+int read_gpio_value(const int id, const char *device, int *value) {
+ char full_name[LARGEST_DEVICE_NAME];
+
+ snprintf(full_name, LARGEST_DEVICE_NAME, device, id);
+ return read_device(full_name, value);
+}
+
+int read_gpio_values(const int start, const int count,
+ const char *device, int *result) {
+ int status = 0;
+ int value;
+
+ *result = 0;
+ for (int i = 0; i < count; i++) {
+ status |= read_gpio_value(start + i, GPIO_PIN_ID, &value);
+ *result |= value << i;
+ }
+ return status;
+}
+
+int read_ids(int *rev_id, int *board_id) {
+ int status = 0;
+ int value;
+
+ status = read_gpio_values(GPIO_REV_ID_START, REV_IDS, GPIO_PIN_ID, rev_id);
+ if (status != 0) {
+ syslog(LOG_INFO, "failed to read rev_id");
+ return status;
+ }
+
+ int board_id_start;
+ if (*rev_id >= REV_ID_NEW_BOARD_ID) {
+ board_id_start = GPIO_BOARD_ID_START_NEW;
+ } else {
+ board_id_start = GPIO_BOARD_ID_START;
+ }
+
+ status = read_gpio_values(board_id_start, BOARD_IDS, GPIO_PIN_ID, board_id);
+ if (status != 0) {
+ syslog(LOG_INFO, "failed to read board_id");
+ }
+ return status;
+}
+
+bool is_two_fan_board(bool verbose) {
+ struct wedge_eeprom_st eeprom;
+ /* Retrieve the board type from EEPROM */
+ if (wedge_eeprom_parse(NULL, &eeprom) == 0) {
+ /* able to parse EEPROM */
+ if (verbose) {
+ syslog(LOG_INFO, "board type is %s", eeprom.fbw_location);
+ }
+ /* only WEDGE is NOT two-fan board */
+ return strncasecmp(eeprom.fbw_location, "wedge",
+ sizeof(eeprom.fbw_location));
+ } else {
+ int status;
+ int board_id = 0;
+ int rev_id = 0;
+ /*
+ * Could not parse EEPROM. Most likely, it is an old HW without EEPROM.
+ * In this case, use board ID to distinguish if it is wedge or 6-pack.
+ */
+ status = read_ids(&rev_id, &board_id);
+ if (verbose) {
+ syslog(LOG_INFO, "rev ID %d, board id %d", rev_id, board_id);
+ }
+ if (status == 0 && board_id != 0xf) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+#endif
+
+int read_fan_value(const int fan, const char *device, int *value) {
+ char device_name[LARGEST_DEVICE_NAME];
+ char output_value[LARGEST_DEVICE_NAME];
+ char full_name[LARGEST_DEVICE_NAME];
+
+ snprintf(device_name, LARGEST_DEVICE_NAME, device, fan);
+ snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name);
+ return read_device(full_name, value);
+}
+
+int write_fan_value(const int fan, const char *device, const int value) {
+ char full_name[LARGEST_DEVICE_NAME];
+ char device_name[LARGEST_DEVICE_NAME];
+ char output_value[LARGEST_DEVICE_NAME];
+
+ snprintf(device_name, LARGEST_DEVICE_NAME, device, fan);
+ snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name);
+ snprintf(output_value, LARGEST_DEVICE_NAME, "%d", value);
+ return write_device(full_name, output_value);
+}
+
+/* Return fan speed as a percentage of maximum -- not necessarily linear. */
+
+int fan_rpm_to_pct(const struct rpm_to_pct_map *table,
+ const int table_len,
+ int rpm) {
+ int i;
+
+ for (i = 0; i < table_len; i++) {
+ if (table[i].rpm > rpm) {
+ break;
+ }
+ }
+
+ /*
+ * If the fan RPM is lower than the lowest value in the table,
+ * we may have a problem -- fans can only go so slow, and it might
+ * have stopped. In this case, we'll return an interpolated
+ * percentage, as just returning zero is even more problematic.
+ */
+
+ if (i == 0) {
+ return (rpm * table[i].pct) / table[i].rpm;
+ } else if (i == table_len) { // Fell off the top?
+ return table[i - 1].pct;
+ }
+
+ // Interpolate the right percentage value:
+
+ int percent_diff = table[i].pct - table[i - 1].pct;
+ int rpm_diff = table[i].rpm - table[i - 1].rpm;
+ int fan_diff = table[i].rpm - rpm;
+
+ return table[i].pct - (fan_diff * percent_diff / rpm_diff);
+}
+
+int fan_speed_okay(const int fan, const int speed, const int slop) {
+ int front_fan, rear_fan;
+ int front_pct, rear_pct;
+ int real_fan;
+ int okay;
+
+ /*
+ * The hardware fan numbers are different from the physical order
+ * in the box, so we have to map them:
+ */
+
+ real_fan = fan_to_rpm_map[fan];
+
+ front_fan = 0;
+ read_fan_value(real_fan, "tacho%d_rpm", &front_fan);
+ front_pct = fan_rpm_to_pct(rpm_front_map, FRONT_MAP_SIZE, front_fan);
+#ifdef BACK_TO_BACK_FANS
+ rear_fan = 0;
+ read_fan_value(real_fan + REAR_FAN_OFFSET, "tacho%d_rpm", &rear_fan);
+ rear_pct = fan_rpm_to_pct(rpm_rear_map, REAR_MAP_SIZE, rear_fan);
+#endif
+
+
+ /*
+ * If the fans are broken, the measured rate will be rather
+ * different from the requested rate, and we can turn up the
+ * rest of the fans to compensate. The slop is the percentage
+ * of error that we'll tolerate.
+ *
+ * XXX: I suppose that we should only measure negative values;
+ * running too fast isn't really a problem.
+ */
+
+#ifdef BACK_TO_BACK_FANS
+ okay = (abs(front_pct - speed) * 100 / speed < slop &&
+ abs(rear_pct - speed) * 100 / speed < slop);
+#else
+ okay = (abs(front_pct - speed) * 100 / speed < slop);
+#endif
+
+ if (!okay || verbose) {
+ syslog(!okay ? LOG_ALERT : LOG_INFO,
+#ifdef BACK_TO_BACK_FANS
+ "fan %d rear %d (%d%%), front %d (%d%%), expected %d",
+#else
+ "fan %d %d RPM (%d%%), expected %d",
+#endif
+ fan,
+#ifdef BACK_TO_BACK_FANS
+ rear_fan,
+ rear_pct,
+#endif
+ front_fan,
+ front_pct,
+ speed);
+ }
+
+ return okay;
+}
+
+/* Set fan speed as a percentage */
+
+int write_fan_speed(const int fan, const int value) {
+ /*
+ * The hardware fan numbers for pwm control are different from
+ * both the physical order in the box, and the mapping for reading
+ * the RPMs per fan, above.
+ */
+
+ int real_fan = fan_to_pwm_map[fan];
+
+ if (value == 0) {
+ return write_fan_value(real_fan, "pwm%d_en", 0);
+ } else {
+ int unit = value * PWM_UNIT_MAX / 100;
+ int status;
+
+ if (unit == PWM_UNIT_MAX)
+ unit = 0;
+
+ if ((status = write_fan_value(real_fan, "pwm%d_type", 0)) != 0 ||
+ (status = write_fan_value(real_fan, "pwm%d_rising", 0)) != 0 ||
+ (status = write_fan_value(real_fan, "pwm%d_falling", unit)) != 0 ||
+ (status = write_fan_value(real_fan, "pwm%d_en", 1)) != 0) {
+ return status;
+ }
+ }
+}
+
+/* Set up fan LEDs */
+
+int write_fan_led(const int fan, const char *color)
+{
+#ifdef CONFIG_WEDGE
+ return write_device(fan_led[fan], color);
+#else
+ return 0;
+#endif
+}
+
+int server_shutdown(const char *why) {
+ int fan;
+ for (fan = 0; fan < total_fans; fan++) {
+ write_fan_speed(fan + fan_offset, fan_max);
+ }
+
+ syslog(LOG_EMERG, "Shutting down: %s", why);
+ write_device(GPIO_USERVER_POWER_DIRECTION, "out");
+ write_device(GPIO_USERVER_POWER, "0");
+#ifdef CONFIG_WEDGE
+ /*
+ * Putting T2 in reset generates a non-maskable interrupt to uS,
+ * the kernel running on uS might panic depending on its version.
+ * sleep 5s here to make sure uS is completely down.
+ */
+ sleep(5);
+
+ if (write_device(GPIO_T2_POWER_DIRECTION, "out") ||
+ write_device(GPIO_T2_POWER, "1")) {
+ /*
+ * We're here because something has gone badly wrong. If we
+ * didn't manage to shut down the T2, cut power to the whole box,
+ * using the PMBus OPERATION register. This will require a power
+ * cycle (removal of both power inputs) to recover.
+ */
+ syslog(LOG_EMERG, "T2 power off failed; turning off via ADM1278");
+ system("rmmod adm1275");
+ system("i2cset -y 12 0x10 0x01 00");
+ }
+
+#else
+ // TODO(7088822): try throttling, then shutting down server.
+ syslog(LOG_EMERG, "Need to implement actual shutdown!\n");
+#endif
+
+ /*
+ * We have to stop the watchdog, or the system will be automatically
+ * rebooted some seconds after fand exits (and stops kicking the
+ * watchdog).
+ */
+
+ stop_watchdog();
+
+ sleep(2);
+ exit(2);
+}
+
+/* Gracefully shut down on receipt of a signal */
+
+void fand_interrupt(int sig)
+{
+ int fan;
+ for (fan = 0; fan < total_fans; fan++) {
+ write_fan_speed(fan + fan_offset, fan_max);
+ }
+
+ syslog(LOG_ALERT, "Shutting down fand on signal %s", strsignal(sig));
+ if (sig == SIGUSR1) {
+ stop_watchdog();
+ }
+ exit(3);
+}
+
+int main(int argc, char **argv) {
+ /* Sensor values */
+
+#ifdef CONFIG_WEDGE
+ int intake_temp;
+ int exhaust_temp;
+ int t2_temp;
+ int userver_temp;
+#else
+ float intake_temp;
+ float exhaust_temp;
+ float userver_temp;
+#endif
+
+ int fan_speed = fan_high;
+ int bad_reads = 0;
+ int fan_failure = 0;
+ int fan_speed_changes = 0;
+ int old_speed;
+
+ int fan_bad[FANS];
+ int fan;
+
+ unsigned log_count = 0; // How many times have we logged our temps?
+ int opt;
+ int prev_fans_bad = 0;
+
+ struct sigaction sa;
+
+ sa.sa_handler = fand_interrupt;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+
+ // Start writing to syslog as early as possible for diag purposes.
+
+ openlog("fand", LOG_CONS, LOG_DAEMON);
+
+#ifdef CONFIG_WEDGE
+ if (is_two_fan_board(false)) {
+ /* Alternate, two fan configuration */
+ total_fans = 2;
+ fan_offset = 2; /* fan 3 is the first */
+
+ fan_low = SIXPACK_FAN_LOW;
+ fan_medium = SIXPACK_FAN_MEDIUM;
+ fan_high = SIXPACK_FAN_HIGH;
+ fan_max = SIXPACK_FAN_MAX;
+ fan_speed = fan_high;
+ }
+#endif
+
+ while ((opt = getopt(argc, argv, "l:m:h:b:t:r:v")) != -1) {
+ switch (opt) {
+ case 'l':
+ fan_low = atoi(optarg);
+ break;
+ case 'm':
+ fan_medium = atoi(optarg);
+ break;
+ case 'h':
+ fan_high = atoi(optarg);
+ break;
+ case 'b':
+ temp_bottom = INTERNAL_TEMPS(atoi(optarg));
+ break;
+ case 't':
+ temp_top = INTERNAL_TEMPS(atoi(optarg));
+ break;
+ case 'r':
+ report_temp = atoi(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind > argc) {
+ usage();
+ }
+
+ if (temp_bottom > temp_top) {
+ fprintf(stderr,
+ "Should temp-bottom (%d) be higher than "
+ "temp-top (%d)? Starting anyway.\n",
+ EXTERNAL_TEMPS(temp_bottom),
+ EXTERNAL_TEMPS(temp_top));
+ }
+
+ if (fan_low > fan_medium || fan_low > fan_high || fan_medium > fan_high) {
+ fprintf(stderr,
+ "fan RPMs not strictly increasing "
+ "-- %d, %d, %d, starting anyway\n",
+ fan_low,
+ fan_medium,
+ fan_high);
+ }
+
+ daemon(1, 0);
+
+ if (verbose) {
+ syslog(LOG_DEBUG, "Starting up; system should have %d fans.",
+ total_fans);
+ }
+
+ for (fan = 0; fan < total_fans; fan++) {
+ fan_bad[fan] = 0;
+ write_fan_speed(fan + fan_offset, fan_speed);
+ write_fan_led(fan + fan_offset, FAN_LED_BLUE);
+ }
+
+#ifdef CONFIG_YOSEMITE
+ /* Ensure that we can read from sensors before proceeding. */
+
+ while (yosemite_sensor_read(1, BIC_SENSOR_SOC_TEMP, &userver_temp))
+ syslog(LOG_DEBUG, "Failed reading of SOC_TEMP.");
+#endif
+
+ /* Start watchdog in manual mode */
+ start_watchdog(0);
+
+ /* Set watchdog to persistent mode so timer expiry will happen independent
+ * of this process's liveliness. */
+ set_persistent_watchdog(WATCHDOG_SET_PERSISTENT);
+
+ sleep(5); /* Give the fans time to come up to speed */
+
+ while (1) {
+ int max_temp;
+ old_speed = fan_speed;
+
+ /* Read sensors */
+
+#ifdef CONFIG_WEDGE
+ read_temp(INTAKE_TEMP_DEVICE, &intake_temp);
+ read_temp(EXHAUST_TEMP_DEVICE, &exhaust_temp);
+ read_temp(T2_TEMP_DEVICE, &t2_temp);
+ read_temp(USERVER_TEMP_DEVICE, &userver_temp);
+
+ /*
+ * uServer can be powered down, but all of the rest of the sensors
+ * should be readable at any time.
+ */
+
+ if ((intake_temp == BAD_TEMP || exhaust_temp == BAD_TEMP ||
+ t2_temp == BAD_TEMP)) {
+ bad_reads++;
+ }
+#else
+ userver_temp = BAD_TEMP;
+ if (yosemite_sensor_read(1, SP_SENSOR_INLET_TEMP, &intake_temp) ||
+ yosemite_sensor_read(1, SP_SENSOR_OUTLET_TEMP, &exhaust_temp))
+ bad_reads++;
+
+ /*
+ * There are a number of 1S servers; any or all of them
+ * could be powered off and returning no values. Ignore these
+ * invalid values.
+ */
+ for (int node = 1; node <= TOTAL_1S_SERVERS; node++) {
+ float new_temp;
+ if (!yosemite_sensor_read(node, BIC_SENSOR_SOC_TEMP, &new_temp)) {
+ if (userver_temp < new_temp) {
+ userver_temp = new_temp;
+ }
+ }
+ }
+#endif
+
+ if (bad_reads > BAD_READ_THRESHOLD) {
+ server_shutdown("Some sensors couldn't be read");
+ }
+
+ if (log_count++ % report_temp == 0) {
+ syslog(LOG_DEBUG,
+#ifdef CONFIG_WEDGE
+ "Temp intake %d, t2 %d, "
+ " userver %d, exhaust %d, "
+ "fan speed %d, speed changes %d",
+#else
+ "Temp intake %f, max server %f, exhaust %f, "
+ "fan speed %d, speed changes %d",
+#endif
+ intake_temp,
+#ifdef CONFIG_WEDGE
+ t2_temp,
+#endif
+ userver_temp,
+ exhaust_temp,
+ fan_speed,
+ fan_speed_changes);
+ }
+
+ /* Protection heuristics */
+
+ if (intake_temp > INTAKE_LIMIT) {
+ server_shutdown("Intake temp limit reached");
+ }
+
+#ifdef CONFIG_WEDGE
+ if (t2_temp > T2_LIMIT) {
+ server_shutdown("T2 temp limit reached");
+ }
+#endif
+
+ if (userver_temp + USERVER_TEMP_FUDGE > USERVER_LIMIT) {
+ server_shutdown("uServer temp limit reached");
+ }
+
+ /*
+ * Calculate change needed -- we should eventually
+ * do something more sophisticated, like PID.
+ *
+ * We should use the intake temperature to adjust this
+ * as well.
+ */
+
+#ifdef CONFIG_WEDGE
+ if (t2_temp > userver_temp + USERVER_TEMP_FUDGE) {
+ max_temp = t2_temp;
+ } else {
+ max_temp = userver_temp + USERVER_TEMP_FUDGE;
+ }
+#else
+ /* Yosemite could have no servers turned on, so ignore that case. */
+ if (userver_temp + USERVER_TEMP_FUDGE > exhaust_temp) {
+ max_temp = userver_temp + USERVER_TEMP_FUDGE;
+ } else {
+ max_temp = exhaust_temp;
+ }
+#endif
+
+ /*
+ * If recovering from a fan problem, spin down fans gradually in case
+ * temperatures are still high. Gradual spin down also reduces wear on
+ * the fans.
+ */
+ if (fan_speed == fan_max) {
+ if (fan_failure == 0) {
+ fan_speed = fan_high;
+ }
+ } else if (fan_speed == fan_high) {
+ if (max_temp + COOLDOWN_SLOP < temp_top) {
+ fan_speed = fan_medium;
+ }
+ } else if (fan_speed == fan_medium) {
+ if (max_temp > temp_top) {
+ fan_speed = fan_high;
+ } else if (max_temp + COOLDOWN_SLOP < temp_bottom) {
+ fan_speed = fan_low;
+ }
+ } else {/* low */
+ if (max_temp > temp_bottom) {
+ fan_speed = fan_medium;
+ }
+ }
+
+ /*
+ * Update fans only if there are no failed ones. If any fans failed
+ * earlier, all remaining fans should continue to run at max speed.
+ */
+
+ if (fan_failure == 0 && fan_speed != old_speed) {
+ syslog(LOG_NOTICE,
+ "Fan speed changing from %d to %d",
+ old_speed,
+ fan_speed);
+ fan_speed_changes++;
+ for (fan = 0; fan < total_fans; fan++) {
+ write_fan_speed(fan + fan_offset, fan_speed);
+ }
+ }
+
+ /*
+ * Wait for some change. Typical I2C temperature sensors
+ * only provide a new value every second and a half, so
+ * checking again more quickly than that is a waste.
+ *
+ * We also have to wait for the fan changes to take effect
+ * before measuring them.
+ */
+
+ sleep(5);
+
+ /* Check fan RPMs */
+
+ for (fan = 0; fan < total_fans; fan++) {
+ /*
+ * Make sure that we're within some percentage
+ * of the requested speed.
+ */
+ if (fan_speed_okay(fan + fan_offset, fan_speed, FAN_FAILURE_OFFSET)) {
+ if (fan_bad[fan] > FAN_FAILURE_THRESHOLD) {
+ write_fan_led(fan + fan_offset, FAN_LED_BLUE);
+ syslog(LOG_NOTICE,
+ "Fan %d has recovered",
+ fan);
+ }
+ fan_bad[fan] = 0;
+ } else {
+ fan_bad[fan]++;
+ }
+ }
+
+ fan_failure = 0;
+ for (fan = 0; fan < total_fans; fan++) {
+ if (fan_bad[fan] > FAN_FAILURE_THRESHOLD) {
+ fan_failure++;
+ write_fan_led(fan + fan_offset, FAN_LED_RED);
+ }
+ }
+
+ if (fan_failure > 0) {
+ if (prev_fans_bad != fan_failure) {
+ syslog(LOG_ALERT, "%d fans failed", fan_failure);
+ }
+
+ /*
+ * If fans are bad, we need to blast all of the
+ * fans at 100%; we don't bother to turn off
+ * the bad fans, in case they are all that is left.
+ *
+ * Note that we have a temporary bug with setting fans to
+ * 100% so we only do fan_max = 99%.
+ */
+
+ fan_speed = fan_max;
+ for (fan = 0; fan < total_fans; fan++) {
+ write_fan_speed(fan + fan_offset, fan_speed);
+ }
+
+ if (fan_failure == total_fans) {
+ int count = 0;
+ for (fan = 0; fan < total_fans; fan++) {
+ if (fan_bad[fan] > FAN_SHUTDOWN_THRESHOLD)
+ count++;
+ }
+ if (count == total_fans) {
+ server_shutdown("all fans are bad for more than 12 cycles");
+ }
+ }
+
+
+ /*
+ * Fans can be hot swapped and replaced; in which case the fan daemon
+ * will automatically detect the new fan and (assuming the new fan isn't
+ * itself faulty), automatically readjust the speeds for all fans down
+ * to a more suitable rpm. The fan daemon does not need to be restarted.
+ */
+ }
+
+ /* Suppress multiple warnings for similar number of fan failures. */
+ prev_fans_bad = fan_failure;
+
+ /* if everything is fine, restart the watchdog countdown. If this process
+ * is terminated, the persistent watchdog setting will cause the system
+ * to reboot after the watchdog timeout. */
+ kick_watchdog();
+ }
+}
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp
new file mode 100644
index 0000000..ebb390a
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp
@@ -0,0 +1,201 @@
+/*
+ * watchdog
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "watchdog.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define WATCHDOG_START_KEY "x"
+#define WATCHDOG_STOP_KEY "X"
+/* The "magic close" character (as defined in Linux watchdog specs). */
+#define WATCHDOG_PERSISTENT_KEY "V"
+#define WATCHDOG_NON_PERSISTENT_KEY "a"
+
+static int watchdog_dev = -1;
+
+/* This is needed to prevent rapid consecutive stop/start watchdog calls from
+ * generating multiple threads. */
+static int watchdog_started = 0;
+
+static const char* watchdog_kick_key = WATCHDOG_PERSISTENT_KEY;
+static pthread_t watchdog_tid;
+static pthread_mutex_t watchdog_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Forward declarations. */
+static void* watchdog_thread(void* args);
+static int kick_watchdog_unsafe();
+
+/*
+ * When started, this background thread will constantly reset the watchdog
+ * at every 5 second interval.
+ */
+
+static void* watchdog_thread(void* args) {
+
+ pthread_detach(pthread_self());
+
+ /* Make sure another instance of the thread hasn't already been started. */
+ pthread_mutex_lock(&watchdog_lock);
+ if (watchdog_started) {
+ goto done;
+ } else {
+ watchdog_started = 1;
+ }
+ pthread_mutex_unlock(&watchdog_lock);
+
+ /* Actual loop for refreshing the watchdog timer. */
+ while (1) {
+ pthread_mutex_lock(&watchdog_lock);
+ if (watchdog_dev != -1) {
+ kick_watchdog_unsafe();
+ } else {
+ break;
+ }
+ pthread_mutex_unlock(&watchdog_lock);
+ sleep(5);
+ }
+
+ /* Broke out of loop because watchdog was stopped. */
+ watchdog_started = 0;
+done:
+ pthread_mutex_unlock(&watchdog_lock);
+ return NULL;
+}
+
+/*
+ * Starts the watchdog timer. timer counts down and restarts the ARM chip
+ * upon timeout. use kick_watchdog() to restart the timer.
+ *
+ * Returns: 1 on success; 0 otherwise.
+ */
+
+int start_watchdog(const int auto_mode) {
+ int status;
+
+ pthread_mutex_lock(&watchdog_lock);
+
+ /* Don't start the watchdog again if it has already been started. */
+ if (watchdog_dev != -1) {
+ while ((status = write(watchdog_dev, WATCHDOG_START_KEY, 1)) == 0
+ && errno == EINTR);
+ pthread_mutex_unlock(&watchdog_lock);
+ syslog(LOG_ALERT, "system watchdog already started.\n");
+ return 0;
+ }
+
+ while (((watchdog_dev = open("/dev/watchdog", O_WRONLY)) == -1) &&
+ errno == EINTR);
+
+ /* Fail if watchdog device is invalid or if the user asked for auto
+ * mode and the thread failed to spawn. */
+ if ((watchdog_dev == -1) ||
+ (auto_mode == 1 && watchdog_started == 0 &&
+ pthread_create(&watchdog_tid, NULL, watchdog_thread, NULL) != 0)) {
+ goto fail;
+ }
+
+ while ((status = write(watchdog_dev, WATCHDOG_START_KEY, 1)) == 0
+ && errno == EINTR);
+ pthread_mutex_unlock(&watchdog_lock);
+ syslog(LOG_INFO, "system watchdog started.\n");
+ return 1;
+
+fail:
+ if (watchdog_dev != -1) {
+ close(watchdog_dev);
+ watchdog_dev = -1;
+ }
+
+ pthread_mutex_unlock(&watchdog_lock);
+ syslog(LOG_ALERT, "system watchdog failed to start!\n");
+ return 0;
+}
+
+/*
+ * Toggles between watchdog persistent modes. In persistent mode, the watchdog
+ * timer will continue to tick even after process shutdown. Under non-
+ * persistent mode, the watchdog timer will automatically be disabled when the
+ * process shuts down.
+ */
+void set_persistent_watchdog(enum watchdog_persistent_en persistent) {
+ switch (persistent) {
+ case WATCHDOG_SET_PERSISTENT:
+ watchdog_kick_key = WATCHDOG_PERSISTENT_KEY;
+ break;
+ default:
+ watchdog_kick_key = WATCHDOG_NON_PERSISTENT_KEY;
+ break;
+ }
+ kick_watchdog();
+}
+
+/*
+ * Restarts the countdown timer on the watchdog, delaying restart by another
+ * timeout period (default: 11 seconds as configured in the device driver).
+ *
+ * This function assumes the watchdog lock has already been acquired and is
+ * only used internally within the watchdog code.
+ *
+ * Returns 1 on success; 0 or -1 indicates failure (check errno).
+ */
+
+static int kick_watchdog_unsafe() {
+ int status = 0;
+ if (watchdog_dev != -1) {
+ while ((status = write(watchdog_dev, watchdog_kick_key, 1)) == 0
+ && errno == EINTR);
+ }
+ return status;
+}
+
+/*
+ * Acquires the watchdog lock and resets the watchdog atomically. For use by
+ * library users.
+ */
+
+int kick_watchdog() {
+ int result;
+ pthread_mutex_lock(&watchdog_lock);
+ result = kick_watchdog_unsafe();
+ pthread_mutex_unlock(&watchdog_lock);
+
+ return result;
+}
+
+/* Shuts down the watchdog gracefully and disables the watchdog timer so that
+ * restarts no longer happen.
+ */
+
+void stop_watchdog() {
+ int status;
+ pthread_mutex_lock(&watchdog_lock);
+ if (watchdog_dev != -1) {
+ while ((status = write(watchdog_dev, WATCHDOG_STOP_KEY, 1)) == 0
+ && errno == EINTR);
+ close(watchdog_dev);
+ watchdog_dev = -1;
+ syslog(LOG_INFO, "system watchdog stopped.\n");
+ }
+ pthread_mutex_unlock(&watchdog_lock);
+}
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.h b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.h
new file mode 100644
index 0000000..19b9944
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.h
@@ -0,0 +1,60 @@
+/*
+ * watchdog
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Utility library to handle the aspeed watchdog. Only one watchdog
+ * should be in use at any time throughout the entire system (multiple users
+ * will not cause adverse effects but the behavior of the watchdog becomes
+ * undefined).
+ *
+ * The watchdog can be started in either manual or automatic mode. In manual
+ * mode, the watchdog has to be constantly reset by the user via the
+ * kick_watchdog() function. Under automatic mode, the watchdog will
+ * run in a separate thread and reset the timer on its own so no intervention
+ * is required from the user.
+ *
+ * In both modes, the watchdog timer will not stop when the process is
+ * terminated, unless a call to stop_watchdog() has been made beforehand, or
+ * if the user runs in manual mode and uses a non persistent watchdog kick.
+ *
+ * The default timeout for the watchdog is 11 seconds. When this time period
+ * elapses, the ARM chip is restarted and the kernel is rebooted. Other
+ * hardware state is not reset, so this may introduce strange behavior on
+ * reboot (example: an I2C bus may be left in the open state, triggering
+ * constant interrupts). In rare cases, this could result in the kernel
+ * failing to fully restart itself and thus preclude the possibility of
+ * reinitializing the watchdog timer. Someone will then have to go over and
+ * physically restart the machine.
+ *
+ * The alternative to the soft reset is to request the watchdog device driver
+ * for a hard reset on timeout. However this will stop the fans. If the
+ * kernel fails to fully boot and restart the fan daemon, the system could
+ * overheat. For this reason, we've chosen to take the risk of a stuck soft
+ * reset instead.
+ *
+ */
+
+/* Forward declarations. */
+int start_watchdog(const int auto_mode);
+enum watchdog_persistent_en {
+ WATCHDOG_SET_PERSISTENT,
+ WATCHDOG_SET_NONPERSISTENT,
+};
+void set_persistent_watchdog(enum watchdog_persistent_en persistent);
+int kick_watchdog();
+void stop_watchdog();
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb b/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb
new file mode 100644
index 0000000..1abfaaa
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb
@@ -0,0 +1,61 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "Fan controller"
+DESCRIPTION = "The utilities to control fan."
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://fand.cpp;beginline=6;endline=18;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://README \
+ file://Makefile \
+ file://fand.cpp \
+ file://watchdog.h \
+ file://watchdog.cpp \
+ "
+
+S = "${WORKDIR}"
+
+binfiles = "fand \
+ "
+
+otherfiles = "README"
+
+pkgdir = "fan_ctrl"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ for f in ${binfiles}; do
+ install -m 755 $f ${dst}/$f
+ ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
+ done
+ for f in ${otherfiles}; do
+ install -m 644 $f ${dst}/$f
+ done
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/fan_ctrl ${prefix}/local/bin"
+
+# Inhibit complaints about .debug directories for the fand binary:
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/fruid/files/Makefile b/common/recipes-core/fruid/files/Makefile
new file mode 100644
index 0000000..5c6aff4
--- /dev/null
+++ b/common/recipes-core/fruid/files/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+all: fruid-util
+
+fruid: fruid-util.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o fruid-util
diff --git a/common/recipes-core/fruid/files/fruid-util.c b/common/recipes-core/fruid/files/fruid-util.c
new file mode 100644
index 0000000..3c8d2e1
--- /dev/null
+++ b/common/recipes-core/fruid/files/fruid-util.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openbmc/fruid.h>
+#include <openbmc/pal.h>
+
+/* Print the FRUID in detail */
+void print_fruid_info(fruid_info_t *fruid, const char *name)
+{
+ /* Print format */
+ printf("%-27s: %s", "\nFRU Information",
+ name /* Name of the FRU device */ );
+ printf("%-27s: %s", "\n---------------", "------------------");
+
+ if (fruid->chassis.flag) {
+ printf("%-27s: %s", "\nChassis Type",fruid->chassis.type_str);
+ printf("%-27s: %s", "\nChassis Part",fruid->chassis.part);
+ printf("%-27s: %s", "\nChassis Serial Number",fruid->chassis.serial);
+ printf("%-27s: %s", "\nChassis Custom Data",fruid->chassis.custom);
+ }
+
+ if (fruid->board.flag) {
+ printf("%-27s: %s", "\nBoard Mfg Time",fruid->board.mfg_time_str);
+ printf("%-27s: %s", "\nBoard Manufacturer",fruid->board.mfg);
+ printf("%-27s: %s", "\nBoard Name",fruid->board.name);
+ printf("%-27s: %s", "\nBoard Serial Number",fruid->board.serial);
+ printf("%-27s: %s", "\nBoard Part",fruid->board.part);
+ printf("%-27s: %s", "\nBoard FRU ID",fruid->board.fruid);
+ printf("%-27s: %s", "\nBoard Custom Data",fruid->board.custom);
+ }
+
+ if (fruid->product.flag) {
+ printf("%-27s: %s", "\nProduct Manufacturer",fruid->product.mfg);
+ printf("%-27s: %s", "\nProduct Name",fruid->product.name);
+ printf("%-27s: %s", "\nProduct Part",fruid->product.part);
+ printf("%-27s: %s", "\nProduct Version",fruid->product.version);
+ printf("%-27s: %s", "\nProduct Serial Number",fruid->product.serial);
+ printf("%-27s: %s", "\nProduct Asset Tag",fruid->product.asset_tag);
+ printf("%-27s: %s", "\nProduct FRU ID",fruid->product.fruid);
+ printf("%-27s: %s", "\nProduct Custom Data",fruid->product.custom);
+ }
+
+ printf("\n");
+}
+
+/* Populate and print fruid_info by parsing the fru's binary dump */
+void get_fruid_info(uint8_t fru, char *path, char* name) {
+ int ret;
+ fruid_info_t fruid;
+
+ ret = fruid_parse(path, &fruid);
+ if (ret) {
+ fprintf(stderr, "Failed print FRUID for %s\nCheck syslog for errors!\n",
+ name);
+ } else {
+ print_fruid_info(&fruid, name);
+ free_fruid_info(&fruid);
+ }
+
+}
+
+static int
+print_usage() {
+ printf("Usage: fruid-util [ %s ]\n", pal_fru_list);
+}
+
+/* Utility to just print the FRUID */
+int main(int argc, char * argv[]) {
+
+ int ret;
+ uint8_t fru;
+ char path[64] = {0};
+ char name[64] = {0};
+
+ if (argc != 2) {
+ print_usage();
+ exit(-1);
+ }
+
+ ret = pal_get_fru_id(argv[1], &fru);
+ if (ret < 0) {
+ print_usage();
+ return ret;
+ }
+
+ if (fru == 0) {
+ fru = 1;
+ while (fru <= MAX_NUM_FRUS) {
+ ret = pal_get_fruid_path(fru, path);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_get_fruid_name(fru, name);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (fru == FRU_NIC) {
+ printf("fruid-util does not support nic\n");
+ exit(-1);
+ }
+
+ get_fruid_info(fru, path, name);
+
+ fru++;
+ }
+ } else {
+ ret = pal_get_fruid_path(fru, path);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_get_fruid_name(fru, name);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (fru == FRU_NIC) {
+ printf("fruid-util does not support nic\n");
+ exit(-1);
+ }
+
+ get_fruid_info(fru, path, name);
+ }
+
+ return 0;
+}
diff --git a/common/recipes-core/fruid/fruid_0.1.bb b/common/recipes-core/fruid/fruid_0.1.bb
new file mode 100644
index 0000000..604845f
--- /dev/null
+++ b/common/recipes-core/fruid/fruid_0.1.bb
@@ -0,0 +1,55 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "IPMI FRUID Utilities"
+DESCRIPTION = "Util for ipmi fruid"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://fruid-util.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+LDFLAGS = " -lfruid -lpal "
+DEPENDS = "libfruid libpal "
+
+SRC_URI = "file://Makefile \
+ file://fruid-util.c \
+ "
+
+S = "${WORKDIR}"
+
+binfiles = "fruid-util \
+ "
+
+pkgdir = "fruid"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ for f in ${binfiles}; do
+ install -m 755 $f ${dst}/$f
+ ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
+ done
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/fruid ${prefix}/local/bin"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/ipmbd/files/Makefile b/common/recipes-core/ipmbd/files/Makefile
new file mode 100644
index 0000000..719ccc3
--- /dev/null
+++ b/common/recipes-core/ipmbd/files/Makefile
@@ -0,0 +1,10 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: ipmbd
+
+ipmbd: ipmbd.o
+ $(CC) $(CFLAGS) -pthread -lrt -lipmi -std=gnu99 -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o ipmbd
diff --git a/common/recipes-core/ipmbd/files/ipmbd.c b/common/recipes-core/ipmbd/files/ipmbd.c
new file mode 100644
index 0000000..5ea5af3
--- /dev/null
+++ b/common/recipes-core/ipmbd/files/ipmbd.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This module handles all the IPMB communication protocol
+ * Refer http://www.intel.com/content/www/us/en/servers/ipmi/ipmp-spec-v1-0.html
+ * for more information.
+ *
+ * IPMB packet format is described here for quick reference
+ * Request:
+ * <Responder Slave Address(rsSA)>
+ * <NetFn/ResponderLUN(Netfn/rsLUN)>
+ * <Header Checksum(hdrCksum)>
+ * <Requester Slave Address(rqSA)>
+ * <Requester Sequence Number/RequesterLUN(rqSeq/rqLUN>
+ * <Command>
+ * <Data[0..n]>
+ * <Data Checksum(dataCksum)>
+ * Response:
+ * <Requester Slave Address(rqSA)>
+ * <NetFn/RequesterLUN(Netfn/rqLUN)>
+ * <Header Checksum(hdrCksum)>
+ * <Responder Slave Address(rsSA)>
+ * <Requester Sequence Number/ResponderLUN(rqSeq/rsLUN>
+ * <Command>
+ * <Completion Code(CC)>
+ * <Data[0..n]>
+ * <Data Checksum(dataCksum)>
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <syslog.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <mqueue.h>
+#include <semaphore.h>
+
+#include "facebook/i2c-dev.h"
+#include "openbmc/ipmi.h"
+#include "openbmc/ipmb.h"
+
+//#define DEBUG 0
+
+#define MAX_BYTES 255
+
+#define MQ_IPMB_REQ "/mq_ipmb_req"
+#define MQ_IPMB_RES "/mq_ipmb_res"
+#define MQ_MAX_MSG_SIZE MAX_BYTES
+#define MQ_MAX_NUM_MSGS 10
+
+#define SEQ_NUM_MAX 64
+
+#define I2C_RETRIES_MAX 3
+
+// Structure for i2c file descriptor and socket
+typedef struct _ipmb_sfd_t {
+ int fd;
+ int sock;
+} ipmb_sfd_t;
+
+// Structure for sequence number and buffer
+typedef struct _seq_buf_t {
+ bool in_use; // seq# is being used
+ uint8_t len; // buffer size
+ uint8_t *p_buf; // pointer to buffer
+ sem_t s_seq; // semaphore for thread sync.
+} seq_buf_t;
+
+// Structure for holding currently used sequence number and
+// array of all possible sequence number
+typedef struct _ipmb_sbuf_t {
+ uint8_t curr_seq; // currently used seq#
+ seq_buf_t seq[SEQ_NUM_MAX]; //array of all possible seq# struct.
+} ipmb_sbuf_t;
+
+// Global storage for holding IPMB sequence number and buffer
+ipmb_sbuf_t g_seq;
+
+// mutex to protect global data access
+pthread_mutex_t m_seq;
+
+pthread_mutex_t m_i2c;
+
+#ifdef CONFIG_YOSEMITE
+// Returns the payload ID from IPMB bus routing
+// Slot#1: bus#3, Slot#2: bus#1, Slot#3: bus#7, Slot#4: bus#5
+static uint8_t
+get_payload_id(uint8_t bus_id) {
+ uint8_t payload_id = 0xFF; // Invalid payload ID
+
+ switch(bus_id) {
+ case 1:
+ payload_id = 2;
+ break;
+ case 3:
+ payload_id = 1;
+ break;
+ case 5:
+ payload_id = 4;
+ break;
+ case 7:
+ payload_id = 3;
+ break;
+ default:
+ syslog(LOG_ALERT, "get_payload_id: Wrong bus ID\n");
+ break;
+ }
+
+ return payload_id;
+}
+#endif
+
+// Returns an unused seq# from all possible seq#
+static uint8_t
+seq_get_new(void) {
+ uint8_t ret = -1;
+ uint8_t index;
+
+ pthread_mutex_lock(&m_seq);
+
+ // Search for unused sequence number
+ index = g_seq.curr_seq;
+ do {
+ if (g_seq.seq[index].in_use == false) {
+ // Found it!
+ ret = index;
+ g_seq.seq[index].in_use = true;
+ g_seq.seq[index].len = 0;
+ break;
+ }
+
+ if (++index == SEQ_NUM_MAX) {
+ index = 0;
+ }
+ } while (index != g_seq.curr_seq);
+
+ // Update the current seq num
+ if (ret >= 0) {
+ if (++index == SEQ_NUM_MAX) {
+ index = 0;
+ }
+ g_seq.curr_seq = index;
+ }
+
+ pthread_mutex_unlock(&m_seq);
+
+ return ret;
+}
+
+static int
+i2c_open(uint8_t bus_num) {
+ int fd;
+ char fn[32];
+ int rc;
+
+ snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus_num);
+ fd = open(fn, O_RDWR);
+ if (fd == -1) {
+ syslog(LOG_ALERT, "Failed to open i2c device %s", fn);
+ return -1;
+ }
+
+ rc = ioctl(fd, I2C_SLAVE, BRIDGE_SLAVE_ADDR);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to open slave @ address 0x%x", BRIDGE_SLAVE_ADDR);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static int
+i2c_write(int fd, uint8_t *buf, uint8_t len) {
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ int rc;
+ int i;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BRIDGE_SLAVE_ADDR;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = buf;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ pthread_mutex_lock(&m_i2c);
+
+ for (i = 0; i < I2C_RETRIES_MAX; i++) {
+ rc = ioctl(fd, I2C_RDWR, &data);
+ if (rc < 0) {
+ sleep(1);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to do raw io");
+ pthread_mutex_unlock(&m_i2c);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&m_i2c);
+
+ return 0;
+}
+
+static int
+i2c_slave_open(uint8_t bus_num) {
+ int fd;
+ char fn[32];
+ int rc;
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ uint8_t read_bytes[MAX_BYTES] = { 0 };
+
+ snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus_num);
+ fd = open(fn, O_RDWR);
+ if (fd == -1) {
+ syslog(LOG_ALERT, "Failed to open i2c device %s", fn);
+ return -1;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BMC_SLAVE_ADDR;
+ msg.flags = I2C_S_EN;
+ msg.len = 1;
+ msg.buf = read_bytes;
+ msg.buf[0] = 1;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ rc = ioctl(fd, I2C_SLAVE_RDWR, &data);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to open slave @ address 0x%x", BMC_SLAVE_ADDR);
+ close(fd);
+ }
+
+ return fd;
+}
+
+static int
+i2c_slave_read(int fd, uint8_t *buf, uint8_t *len) {
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ int rc;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BMC_SLAVE_ADDR;
+ msg.flags = 0;
+ msg.len = MAX_BYTES;
+ msg.buf = buf;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ rc = ioctl(fd, I2C_SLAVE_RDWR, &data);
+ if (rc < 0) {
+ return -1;
+ }
+
+ *len = msg.len;
+
+ return 0;
+}
+
+// Thread to handle new requests
+static void*
+ipmb_req_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ mqd_t mq;
+ int fd;
+ int i;
+
+ //Buffers for IPMB transport
+ uint8_t rxbuf[MQ_MAX_MSG_SIZE] = {0};
+ uint8_t txbuf[MQ_MAX_MSG_SIZE] = {0};
+ ipmb_req_t *p_ipmb_req;
+ ipmb_res_t *p_ipmb_res;
+
+ p_ipmb_req = (ipmb_req_t*) rxbuf;
+ p_ipmb_res = (ipmb_res_t*) txbuf;
+
+ //Buffers for IPMI Stack
+ uint8_t rbuf[MQ_MAX_MSG_SIZE] = {0};
+ uint8_t tbuf[MQ_MAX_MSG_SIZE] = {0};
+ ipmi_mn_req_t *p_ipmi_mn_req;
+ ipmi_res_t *p_ipmi_res;
+
+ p_ipmi_mn_req = (ipmi_mn_req_t*) rbuf;
+ p_ipmi_res = (ipmi_res_t*) tbuf;
+
+ uint8_t rlen = 0;
+ uint8_t tlen = 0;
+
+ char mq_ipmb_req[64] = {0};
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, *bnum);
+
+ // Open Queue to receive requests
+ mq = mq_open(mq_ipmb_req, O_RDONLY);
+ if (mq == (mqd_t) -1) {
+ return NULL;
+ }
+
+ // Open the i2c bus for sending response
+ fd = i2c_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_open failure\n");
+ close(mq);
+ return NULL;
+ }
+
+ // Loop to process incoming requests
+ while (1) {
+ if ((rlen = mq_receive(mq, rxbuf, MQ_MAX_MSG_SIZE, NULL)) < 0) {
+ sleep(1);
+ continue;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Received Request of %d bytes\n", rlen);
+ for (i = 0; i < rlen; i++) {
+ syslog(LOG_ALERT, "0x%X", rxbuf[i]);
+ }
+#endif
+
+ // Create IPMI request from IPMB data
+#ifdef CONFIG_YOSEMITE
+ p_ipmi_mn_req->payload_id = get_payload_id(*bnum);
+#else
+ // For single node systems use payload ID as 1
+ p_ipmi_mn_req->payload_id = 0x1;
+#endif
+ p_ipmi_mn_req->netfn_lun = p_ipmb_req->netfn_lun;
+ p_ipmi_mn_req->cmd = p_ipmb_req->cmd;
+
+ memcpy(p_ipmi_mn_req->data, p_ipmb_req->data, rlen - IPMB_HDR_SIZE - IPMI_REQ_HDR_SIZE);
+
+ // Send to IPMI stack and get response
+ // Additional byte as we are adding and passing payload ID for MN support
+ lib_ipmi_handle(rbuf, rlen - IPMB_HDR_SIZE + 1, tbuf, &tlen);
+
+ // Populate IPMB response data from IPMB request
+ p_ipmb_res->req_slave_addr = p_ipmb_req->req_slave_addr;
+ p_ipmb_res->res_slave_addr = p_ipmb_req->res_slave_addr;
+ p_ipmb_res->cmd = p_ipmb_req->cmd;
+ p_ipmb_res->seq_lun = p_ipmb_req->seq_lun;
+
+ // Add IPMI response data
+ p_ipmb_res->netfn_lun = p_ipmi_res->netfn_lun;
+ p_ipmb_res->cc = p_ipmi_res->cc;
+
+ memcpy(p_ipmb_res->data, p_ipmi_res->data, tlen - IPMI_RESP_HDR_SIZE);
+
+ // Calculate Header Checksum
+ p_ipmb_res->hdr_cksum = p_ipmb_res->req_slave_addr +
+ p_ipmb_res->netfn_lun;
+ p_ipmb_res->hdr_cksum = ZERO_CKSUM_CONST - p_ipmb_res->hdr_cksum;
+
+ // Calculate Data Checksum
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] = p_ipmb_res->res_slave_addr +
+ p_ipmb_res->seq_lun +
+ p_ipmb_res->cmd +
+ p_ipmb_res->cc;
+
+ for (i = 0; i < tlen-IPMI_RESP_HDR_SIZE; i++) {
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] += p_ipmb_res->data[i];
+ }
+
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] = ZERO_CKSUM_CONST -
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE];
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Sending Response of %d bytes\n", tlen+IPMB_HDR_SIZE-1);
+ for (i = 1; i < tlen+IPMB_HDR_SIZE; i++) {
+ syslog(LOG_ALERT, "0x%X:", txbuf[i]);
+ }
+#endif
+
+ // Send response back
+ i2c_write(fd, &txbuf[1], tlen+IPMB_HDR_SIZE-1);
+ }
+}
+
+// Thread to handle the incoming responses
+static void*
+ipmb_res_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ uint8_t buf[MQ_MAX_MSG_SIZE] = { 0 };
+ uint8_t len = 0;
+ mqd_t mq;
+ ipmb_res_t *p_res;
+ uint8_t index;
+ char mq_ipmb_res[64] = {0};
+
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, *bnum);
+
+ // Open the message queue
+ mq = mq_open(mq_ipmb_res, O_RDONLY);
+ if (mq == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open fails\n");
+ return NULL;
+ }
+
+ // Loop to wait for incomng response messages
+ while (1) {
+ if ((len = mq_receive(mq, buf, MQ_MAX_MSG_SIZE, NULL)) < 0) {
+ sleep(1);
+ continue;
+ }
+
+ p_res = (ipmb_res_t *) buf;
+
+ // Check the seq# of response
+ index = p_res->seq_lun >> LUN_OFFSET;
+
+ // Check if the response is being waited for
+ pthread_mutex_lock(&m_seq);
+ if (g_seq.seq[index].in_use) {
+ // Copy the response to the requester's buffer
+ memcpy(g_seq.seq[index].p_buf, buf, len);
+ g_seq.seq[index].len = len;
+
+ // Wake up the worker thread to receive the response
+ sem_post(&g_seq.seq[index].s_seq);
+ }
+ pthread_mutex_unlock(&m_seq);
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Received Response of %d bytes\n", len);
+ int i;
+ for (i = 0; i < len; i++) {
+ syslog(LOG_ALERT, "0x%X:", buf[i]);
+ }
+#endif
+ }
+}
+
+// Thread to receive the IPMB messages over i2c bus as a slave
+static void*
+ipmb_rx_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ int fd;
+ uint8_t len;
+ uint8_t tlun;
+ uint8_t buf[MAX_BYTES] = { 0 };
+ mqd_t mq_req, mq_res, tmq;
+ ipmb_req_t *p_req;
+ struct timespec req;
+ struct timespec rem;
+ char mq_ipmb_req[64] = {0};
+ char mq_ipmb_res[64] = {0};
+
+ // Setup wait time
+ req.tv_sec = 0;
+ req.tv_nsec = 10000000;//10mSec
+
+ // Open the i2c bus as a slave
+ fd = i2c_slave_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_slave_open fails\n");
+ goto cleanup;
+ }
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, *bnum);
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, *bnum);
+
+ // Open the message queues for post processing
+ mq_req = mq_open(mq_ipmb_req, O_WRONLY);
+ if (mq_req == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open req fails\n");
+ goto cleanup;
+ }
+
+ mq_res = mq_open(mq_ipmb_res, O_WRONLY);
+ if (mq_res == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open res fails\n");
+ goto cleanup;
+ }
+
+ // Loop that retrieves messages
+ while (1) {
+ // Read messages from i2c driver
+ if (i2c_slave_read(fd, buf, &len) < 0) {
+ nanosleep(&req, &rem);
+ continue;
+ }
+
+ // Check if the messages is request or response
+ // Even NetFn: Request, Odd NetFn: Response
+ p_req = (ipmb_req_t*) buf;
+ tlun = p_req->netfn_lun >> LUN_OFFSET;
+ if (tlun%2) {
+ tmq = mq_res;
+ } else {
+ tmq = mq_req;
+ }
+ // Post message to approriate Queue for further processing
+ if (mq_send(tmq, buf, len, 0)) {
+ syslog(LOG_ALERT, "mq_send failed\n");
+ sleep(1);
+ continue;
+ }
+ }
+
+cleanup:
+ if (fd > 0) {
+ close (fd);
+ }
+
+ if (mq_req > 0) {
+ close(mq_req);
+ }
+
+ if (mq_res > 0) {
+ close(mq_req);
+ }
+}
+
+/*
+ * Function to handle all IPMB requests
+ */
+static void
+ipmb_handle (int fd, unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmb_req_t *req = (ipmb_req_t *) request;
+ ipmb_res_t *res = (ipmb_res_t *) response;
+
+ uint8_t index;
+ struct timespec ts;
+
+ // Allocate right sequence Number
+ index = seq_get_new();
+ if (index < 0) {
+ *res_len = 0;
+ return ;
+ }
+
+ req->seq_lun = index << LUN_OFFSET;
+
+ // Calculate/update dataCksum
+ // Note: dataCkSum byte is last byte
+ int i;
+ for (i = IPMB_DATA_OFFSET; i < req_len-1; i++) {
+ request[req_len-1] += request[i];
+ }
+
+ request[req_len-1] = ZERO_CKSUM_CONST - request[req_len-1];
+
+ // Setup response buffer
+ pthread_mutex_lock(&m_seq);
+ g_seq.seq[index].p_buf = response;
+ pthread_mutex_unlock(&m_seq);
+
+ // Send request over i2c bus
+ // Note: Need not send first byte SlaveAddress automatically added by driver
+ if (i2c_write(fd, &request[1], req_len-1)) {
+ goto ipmb_handle_out;
+ }
+
+ // Wait on semaphore for that sequence Number
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ ts.tv_sec += TIMEOUT_IPMI;
+
+ int ret;
+ ret = sem_timedwait(&g_seq.seq[index].s_seq, &ts);
+ if (ret == -1) {
+ syslog(LOG_ALERT, "No response for sequence number: %d\n", index);
+ *res_len = 0;
+ }
+
+ipmb_handle_out:
+ // Reply to user with data
+ pthread_mutex_lock(&m_seq);
+ *res_len = g_seq.seq[index].len;
+
+ g_seq.seq[index].in_use = false;
+ pthread_mutex_unlock(&m_seq);
+
+ return;
+}
+
+void
+*conn_handler(void *sfd) {
+ ipmb_sfd_t *p_sfd = (ipmb_sfd_t *) sfd;
+
+ int sock = p_sfd->sock;
+ int fd = p_sfd->fd;
+ int n;
+ unsigned char req_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_len = 0;
+
+ n = recv(sock, req_buf, sizeof(req_buf), 0);
+ if (n <= 0) {
+ syslog(LOG_ALERT, "ipmbd: recv() failed with %d\n", n);
+ goto conn_cleanup;
+ }
+
+ ipmb_handle(fd, req_buf, n, res_buf, &res_len);
+
+ if (send(sock, res_buf, res_len, MSG_NOSIGNAL) < 0) {
+ syslog(LOG_ALERT, "ipmbd: send() failed\n");
+ }
+
+conn_cleanup:
+ close(sock);
+ free(p_sfd);
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+// Thread to receive the IPMB lib messages from various apps
+static void*
+ipmb_lib_handler(void *bus_num) {
+ int s, s2, t, len;
+ struct sockaddr_un local, remote;
+ pthread_t tid;
+ ipmb_sfd_t *sfd;
+ int fd;
+ uint8_t *bnum = (uint8_t*) bus_num;
+ char sock_path[20] = {0};
+
+ // Open the i2c bus for sending request
+ fd = i2c_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_open failure\n");
+ return NULL;
+ }
+
+ // Initialize g_seq structure
+ int i;
+ for (i = 0; i < SEQ_NUM_MAX; i++) {
+ g_seq.seq[i].in_use = false;
+ sem_init(&g_seq.seq[i].s_seq, 0, 0);
+ g_seq.seq[i].len = 0;
+ }
+
+ // Initialize mutex to access global structure
+ pthread_mutex_init(&m_seq, NULL);
+
+ if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: socket() failed\n");
+ exit (1);
+ }
+
+ sprintf(sock_path, "%s_%d", SOCK_PATH_IPMB, *bnum);
+
+ local.sun_family = AF_UNIX;
+ strcpy (local.sun_path, sock_path);
+ unlink (local.sun_path);
+ len = strlen (local.sun_path) + sizeof (local.sun_family);
+ if (bind (s, (struct sockaddr *) &local, len) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: bind() failed\n");
+ exit (1);
+ }
+
+ if (listen (s, 5) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: listen() failed\n");
+ exit (1);
+ }
+
+ while(1) {
+ int n;
+ t = sizeof (remote);
+ if ((s2 = accept (s, (struct sockaddr *) &remote, &t)) < 0) {
+ syslog(LOG_ALERT, "ipmbd: accept() failed\n");
+ break;
+ }
+
+ // Creating a worker thread to handle the request
+ // TODO: Need to monitor the server performance with higher load and
+ // see if we need to create pre-defined number of workers and schedule
+ // the requests among them.
+ sfd = (ipmb_sfd_t *) malloc(sizeof(ipmb_sfd_t));
+ sfd->fd = fd;
+ sfd->sock = s2;
+ if (pthread_create(&tid, NULL, conn_handler, (void*) sfd) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ close(s2);
+ continue;
+ }
+
+ pthread_detach(tid);
+ }
+
+ close(s);
+ pthread_mutex_destroy(&m_seq);
+
+ return 0;
+}
+
+int
+main(int argc, char * const argv[]) {
+ pthread_t tid_ipmb_rx;
+ pthread_t tid_req_handler;
+ pthread_t tid_res_handler;
+ pthread_t tid_lib_handler;
+ uint8_t ipmb_bus_num;
+ mqd_t mqd_req, mqd_res;
+ struct mq_attr attr;
+ char mq_ipmb_req[64] = {0};
+ char mq_ipmb_res[64] = {0};
+
+ daemon(1, 0);
+ openlog("ipmbd", LOG_CONS, LOG_DAEMON);
+
+ if (argc != 2) {
+ syslog(LOG_ALERT, "ipmbd: Usage: ipmbd <bus#>");
+ exit(1);
+ }
+
+ ipmb_bus_num = atoi(argv[1]);
+syslog(LOG_ALERT, "ipmbd: bus#:%d\n", ipmb_bus_num);
+
+ pthread_mutex_init(&m_i2c, NULL);
+
+ // Create Message Queues for Request Messages and Response Messages
+ attr.mq_flags = 0;
+ attr.mq_maxmsg = MQ_MAX_NUM_MSGS;
+ attr.mq_msgsize = MQ_MAX_MSG_SIZE;
+ attr.mq_curmsgs = 0;
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, ipmb_bus_num);
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, ipmb_bus_num);
+
+ // Remove the MQ if exists
+ mq_unlink(mq_ipmb_req);
+
+ errno = 0;
+ mqd_req = mq_open(mq_ipmb_req, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &attr);
+ if (mqd_req == (mqd_t) -1) {
+ syslog(LOG_ALERT, "ipmbd: mq_open request failed errno:%d\n", errno);
+ goto cleanup;
+ }
+
+ // Remove the MQ if exists
+ mq_unlink(mq_ipmb_res);
+
+ errno = 0;
+ mqd_res = mq_open(mq_ipmb_res, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &attr);
+ if (mqd_res == (mqd_t) -1) {
+ syslog(LOG_ALERT, "ipmbd: mq_open response failed errno: %d\n", errno);
+ goto cleanup;
+ }
+
+ // Create thread to handle IPMB Requests
+ if (pthread_create(&tid_req_handler, NULL, ipmb_req_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to handle IPMB Responses
+ if (pthread_create(&tid_res_handler, NULL, ipmb_res_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to retrieve ipmb traffic from i2c bus as slave
+ if (pthread_create(&tid_ipmb_rx, NULL, ipmb_rx_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to receive ipmb library requests from apps
+ if (pthread_create(&tid_lib_handler, NULL, ipmb_lib_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+cleanup:
+ if (tid_ipmb_rx > 0) {
+ pthread_join(tid_ipmb_rx, NULL);
+ }
+
+ if (tid_req_handler > 0) {
+ pthread_join(tid_req_handler, NULL);
+ }
+
+ if (tid_res_handler > 0) {
+ pthread_join(tid_res_handler, NULL);
+ }
+
+ if (tid_lib_handler > 0) {
+ pthread_join(tid_lib_handler, NULL);
+ }
+
+ if (mqd_res > 0) {
+ mq_close(mqd_res);
+ mq_unlink(mq_ipmb_res);
+ }
+
+ if (mqd_req > 0) {
+ mq_close(mqd_req);
+ mq_unlink(mq_ipmb_req);
+ }
+
+ pthread_mutex_destroy(&m_i2c);
+
+ return 0;
+}
diff --git a/common/recipes-core/ipmbd/ipmbd_0.1.bb b/common/recipes-core/ipmbd/ipmbd_0.1.bb
new file mode 100644
index 0000000..f5724b0
--- /dev/null
+++ b/common/recipes-core/ipmbd/ipmbd_0.1.bb
@@ -0,0 +1,19 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+
+SUMMARY = "ipmbd tx/rx daemon"
+DESCRIPTION = "The ipmb daemon to receive/transmit messages"
+SECTION = "base"
+PR = "r2"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://ipmbd.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://Makefile \
+ file://ipmbd.c \
+ "
+
+S = "${WORKDIR}"
+DEPENDS += "libipmi libipmb"
+
+binfiles = "ipmbd"
+
+pkgdir = "ipmbd"
diff --git a/common/recipes-core/ipmid/files/Makefile b/common/recipes-core/ipmid/files/Makefile
new file mode 100644
index 0000000..4f0db3d
--- /dev/null
+++ b/common/recipes-core/ipmid/files/Makefile
@@ -0,0 +1,29 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+C_SRCS := $(wildcard *.c)
+C_OBJS := ${C_SRCS:.c=.o}
+
+all: ipmid
+
+ipmid: $(C_OBJS)
+ $(CC) -pthread -lpal -std=c99 -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o ipmid
diff --git a/common/recipes-core/ipmid/files/fruid.h b/common/recipes-core/ipmid/files/fruid.h
new file mode 100644
index 0000000..3580b08
--- /dev/null
+++ b/common/recipes-core/ipmid/files/fruid.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FRUID_H__
+#define __FRUID_H__
+
+int plat_fruid_size(void);
+int plat_fruid_data(int offset, int count, unsigned char *data);
+int plat_fruid_init(void);
+
+#endif /* __FRUID_H__ */
diff --git a/common/recipes-core/ipmid/files/ipmid.c b/common/recipes-core/ipmid/files/ipmid.c
new file mode 100644
index 0000000..c79d3e2
--- /dev/null
+++ b/common/recipes-core/ipmid/files/ipmid.c
@@ -0,0 +1,1412 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This file contains code to support IPMI2.0 Specificaton available @
+ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sdr.h"
+#include "sel.h"
+#include "fruid.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <openbmc/ipmi.h>
+
+// TODO: Once data storage is finalized, the following structure needs
+// to be retrieved/updated from persistant backend storage
+static lan_config_t g_lan_config = { 0 };
+static proc_info_t g_proc_info = { 0 };
+static dimm_info_t g_dimm_info[MAX_NUM_DIMMS] = { 0 };
+
+// TODO: Need to store this info after identifying proper storage
+static sys_info_param_t g_sys_info_params;
+
+// TODO: Based on performance testing results, might need fine grained locks
+// Since the global data is specific to a NetFunction, adding locs at NetFn level
+static pthread_mutex_t m_chassis;
+static pthread_mutex_t m_app;
+static pthread_mutex_t m_storage;
+static pthread_mutex_t m_transport;
+static pthread_mutex_t m_oem;
+static pthread_mutex_t m_oem_1s;
+
+static void ipmi_handle(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len);
+
+/*
+ * Function(s) to handle IPMI messages with NetFn: Chassis
+ */
+// Get Chassis Status (IPMI/Section 28.2)
+static void
+chassis_get_status (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ res->cc = CC_SUCCESS;
+
+ // TODO: Need to obtain current power state and last power event
+ // from platform and return
+ *data++ = 0x01; // Current Power State
+ *data++ = 0x00; // Last Power Event
+ *data++ = 0x40; // Misc. Chassis Status
+ *data++ = 0x00; // Front Panel Button Disable
+
+ res_len = data - &res->data[0];
+}
+
+// Get System Boot Options (IPMI/Section 28.12)
+static void
+chassis_get_boot_options (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res= (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ unsigned char param = req->data[0];
+
+ // Fill response with default values
+ res->cc = CC_SUCCESS;
+ *data++ = 0x01; // Parameter Version
+ *data++ = req->data[0]; // Parameter
+
+ // TODO: Need to store user settings and return
+ switch (param)
+ {
+ case PARAM_SET_IN_PROG:
+ *data++ = 0x00; // Set In Progress
+ break;
+ case PARAM_SVC_PART_SELECT:
+ *data++ = 0x00; // Service Partition Selector
+ break;
+ case PARAM_SVC_PART_SCAN:
+ *data++ = 0x00; // Service Partition Scan
+ break;
+ case PARAM_BOOT_FLAG_CLR:
+ *data++ = 0x00; // BMC Boot Flag Valid Bit Clear
+ break;
+ case PARAM_BOOT_INFO_ACK:
+ *data++ = 0x00; // Write Mask
+ *data++ = 0x00; // Boot Initiator Ack Data
+ break;
+ case PARAM_BOOT_FLAGS:
+ *data++ = 0x00; // Boot Flags
+ *data++ = 0x00; // Boot Device Selector
+ *data++ = 0x00; // Firmwaer Verbosity
+ *data++ = 0x00; // BIOS Override
+ *data++ = 0x00; // Device Instance Selector
+ break;
+ case PARAM_BOOT_INIT_INFO:
+ *data++ = 0x00; // Chanel Number
+ *data++ = 0x00; // Session ID (4 bytes)
+ *data++ = 0x00;
+ *data++ = 0x00;
+ *data++ = 0x00;
+ *data++ = 0x00; // Boot Info Timestamp (4 bytes)
+ *data++ = 0x00;
+ *data++ = 0x00;
+ *data++ = 0x00;
+ break;
+ deault:
+ res->cc = CC_PARAM_OUT_OF_RANGE;
+ break;
+ }
+
+ if (res->cc == CC_SUCCESS) {
+ *res_len = data - &res->data[0];
+ }
+}
+
+// Handle Chassis Commands (IPMI/Section 28)
+static void
+ipmi_handle_chassis (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char cmd = req->cmd;
+
+ pthread_mutex_lock(&m_chassis);
+ switch (cmd)
+ {
+ case CMD_CHASSIS_GET_STATUS:
+ chassis_get_status (response, res_len);
+ break;
+ case CMD_CHASSIS_GET_BOOT_OPTIONS:
+ chassis_get_boot_options (request, response, res_len);
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ break;
+ }
+ pthread_mutex_unlock(&m_chassis);
+}
+
+/*
+ * Function(s) to handle IPMI messages with NetFn: Application
+ */
+// Get Device ID (IPMI/Section 20.1)
+static void
+app_get_device_id (unsigned char *response, unsigned char *res_len)
+{
+
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ res->cc = CC_SUCCESS;
+
+ //TODO: Following data needs to be updated based on platform
+ *data++ = 0x20; // Device ID
+ *data++ = 0x81; // Device Revision
+ *data++ = 0x00; // Firmware Revision Major
+ *data++ = 0x09; // Firmware Revision Minor
+ *data++ = 0x02; // IPMI Version
+ *data++ = 0xBF; // Additional Device Support
+ *data++ = 0x15; // Manufacturer ID1
+ *data++ = 0xA0; // Manufacturer ID2
+ *data++ = 0x00; // Manufacturer ID3
+ *data++ = 0x46; // Product ID1
+ *data++ = 0x31; // Product ID2
+ *data++ = 0x00; // Aux. Firmware Version1
+ *data++ = 0x00; // Aux. Firmware Version2
+ *data++ = 0x00; // Aux. Firmware Version3
+ *data++ = 0x00; // Aux. Firmware Version4
+
+ *res_len = data - &res->data[0];
+}
+
+// Get Self Test Results (IPMI/Section 20.4)
+static void
+app_get_selftest_results (unsigned char *response, unsigned char *res_len)
+{
+
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ res->cc = CC_SUCCESS;
+
+ //TODO: Following data needs to be updated based on self-test results
+ *data++ = 0x55; // Self-Test result
+ *data++ = 0x00; // Extra error info in case of failure
+
+ *res_len = data - &res->data[0];
+}
+
+// Get Device GUID (IPMI/Section 20.8)
+static void
+app_get_device_guid (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ res->cc = 0x00;
+
+ // TODO: Following data is Globaly Unique ID i.e. MAC Address..
+ *data++ = 0x0;
+ *data++ = 0x1;
+ *data++ = 0x2;
+ *data++ = 0x3;
+ *data++ = 0x4;
+ *data++ = 0x5;
+ *data++ = 0x6;
+ *data++ = 0x7;
+ *data++ = 0x8;
+ *data++ = 0x9;
+ *data++ = 0xa;
+ *data++ = 0xb;
+ *data++ = 0xc;
+ *data++ = 0xd;
+ *data++ = 0xe;
+ *data++ = 0xf;
+
+ *res_len = data - &res->data[0];
+}
+
+// Get BMC Global Enables (IPMI/Section 22.2)
+static void
+app_get_global_enables (unsigned char *response, unsigned char *res_len)
+{
+
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ res->cc = CC_SUCCESS;
+
+ *data++ = 0x09; // Global Enable
+
+ *res_len = data - &res->data[0];
+}
+
+// Set System Info Params (IPMI/Section 22.14a)
+static void
+app_set_sys_info_params (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char param = req->data[0];
+
+ res->cc = CC_SUCCESS;
+
+ switch (param)
+ {
+ case SYS_INFO_PARAM_SET_IN_PROG:
+ g_sys_info_params.set_in_prog = req->data[1];
+ break;
+ case SYS_INFO_PARAM_SYSFW_VER:
+ memcpy(g_sys_info_params.sysfw_ver, &req->data[1], SIZE_SYSFW_VER);
+ break;
+ case SYS_INFO_PARAM_SYS_NAME:
+ memcpy(g_sys_info_params.sys_name, &req->data[1], SIZE_SYS_NAME);
+ break;
+ case SYS_INFO_PARAM_PRI_OS_NAME:
+ memcpy(g_sys_info_params.pri_os_name, &req->data[1], SIZE_OS_NAME);
+ break;
+ case SYS_INFO_PARAM_PRESENT_OS_NAME:
+ memcpy(g_sys_info_params.present_os_name, &req->data[1], SIZE_OS_NAME);
+ break;
+ case SYS_INFO_PARAM_PRESENT_OS_VER:
+ memcpy(g_sys_info_params.present_os_ver, &req->data[1], SIZE_OS_VER);
+ break;
+ case SYS_INFO_PARAM_BMC_URL:
+ memcpy(g_sys_info_params.bmc_url, &req->data[1], SIZE_BMC_URL);
+ break;
+ case SYS_INFO_PARAM_OS_HV_URL:
+ memcpy(g_sys_info_params.os_hv_url, &req->data[1], SIZE_OS_HV_URL);
+ break;
+ default:
+ res->cc = CC_INVALID_PARAM;
+ break;
+ }
+
+ return;
+}
+
+// Get System Info Params (IPMI/Section 22.14b)
+static void
+app_get_sys_info_params (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ unsigned char param = req->data[1];
+
+ // Fill default return values
+ res->cc = CC_SUCCESS;
+ *data++ = 1; // Parameter revision
+
+ switch (param)
+ {
+ case SYS_INFO_PARAM_SET_IN_PROG:
+ *data++ = g_sys_info_params.set_in_prog;
+ break;
+ case SYS_INFO_PARAM_SYSFW_VER:
+ memcpy(data, g_sys_info_params.sysfw_ver, SIZE_SYSFW_VER);
+ data += SIZE_SYSFW_VER;
+ break;
+ case SYS_INFO_PARAM_SYS_NAME:
+ memcpy(data, g_sys_info_params.sys_name, SIZE_SYS_NAME);
+ data += SIZE_SYS_NAME;
+ break;
+ case SYS_INFO_PARAM_PRI_OS_NAME:
+ memcpy(data, g_sys_info_params.pri_os_name, SIZE_OS_NAME);
+ data += SIZE_OS_NAME;
+ break;
+ case SYS_INFO_PARAM_PRESENT_OS_NAME:
+ memcpy(data, g_sys_info_params.present_os_name, SIZE_OS_NAME);
+ data += SIZE_OS_NAME;
+ break;
+ case SYS_INFO_PARAM_PRESENT_OS_VER:
+ memcpy(data, g_sys_info_params.present_os_ver, SIZE_OS_VER);
+ data += SIZE_OS_VER;
+ break;
+ case SYS_INFO_PARAM_BMC_URL:
+ memcpy(data, g_sys_info_params.bmc_url, SIZE_BMC_URL);
+ data += SIZE_BMC_URL;
+ break;
+ case SYS_INFO_PARAM_OS_HV_URL:
+ memcpy(data, g_sys_info_params.os_hv_url, SIZE_OS_HV_URL);
+ data += SIZE_OS_HV_URL;
+ break;
+ default:
+ res->cc = CC_INVALID_PARAM;
+ break;
+ }
+
+ if (res->cc == CC_SUCCESS) {
+ *res_len = data - &res->data[0];
+ }
+
+ return;
+}
+
+// Handle Appliction Commands (IPMI/Section 20)
+static void
+ipmi_handle_app (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char cmd = req->cmd;
+
+ pthread_mutex_lock(&m_app);
+ switch (cmd)
+ {
+ case CMD_APP_GET_DEVICE_ID:
+ app_get_device_id (response, res_len);
+ break;
+ case CMD_APP_GET_SELFTEST_RESULTS:
+ app_get_selftest_results (response, res_len);
+ break;
+ case CMD_APP_GET_DEVICE_GUID:
+ case CMD_APP_GET_SYSTEM_GUID:
+ // Get Device GUID and Get System GUID returns same data
+ // from IPMI stack. FYI, Get System GUID will have to be
+ // sent with in an IPMI session that includes session info
+ app_get_device_guid (response, res_len);
+ break;
+ case CMD_APP_GET_GLOBAL_ENABLES:
+ app_get_global_enables (response, res_len);
+ break;
+ case CMD_APP_SET_SYS_INFO_PARAMS:
+ app_set_sys_info_params (request, response, res_len);
+ break;
+ case CMD_APP_GET_SYS_INFO_PARAMS:
+ app_get_sys_info_params (request, response, res_len);
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ break;
+ }
+ pthread_mutex_unlock(&m_app);
+}
+
+/*
+ * Function(s) to handle IPMI messages with NetFn: Storage
+ */
+
+static void
+storage_get_fruid_info(unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ int size = plat_fruid_size();
+
+ res->cc = CC_SUCCESS;
+
+ *data++ = size & 0xFF; // FRUID size LSB
+ *data++ = (size >> 8) & 0xFF; // FRUID size MSB
+ *data++ = 0x00; // Device accessed by bytes
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_get_fruid_data(unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ int offset = req->data[1] + (req->data[2] << 8);
+ int count = req->data[3];
+
+ int ret = plat_fruid_data(offset, count, &(res->data[1]));
+ if (ret) {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ } else {
+ res->cc = CC_SUCCESS;
+ *data++ = count;
+ data += count;
+ }
+
+ if (res->cc == CC_SUCCESS) {
+ *res_len = data - &res->data[0];
+ }
+ return;
+}
+
+static void
+storage_get_sdr_info (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ int num_entries; // number of sdr records
+ int free_space; // free space in SDR device in bytes
+ time_stamp_t ts_recent_add; // Recent Addition Timestamp
+ time_stamp_t ts_recent_erase; // Recent Erasure Timestamp
+
+ // Use platform APIs to get SDR information
+ num_entries = sdr_num_entries ();
+ free_space = sdr_free_space ();
+ sdr_ts_recent_add (&ts_recent_add);
+ sdr_ts_recent_erase (&ts_recent_erase);
+
+ res->cc = CC_SUCCESS;
+
+ *data++ = IPMI_SDR_VERSION; // SDR version
+ *data++ = num_entries & 0xFF; // number of sdr entries
+ *data++ = (num_entries >> 8) & 0xFF;
+ *data++ = free_space & 0xFF; // Free SDR Space
+ *data++ = (free_space >> 8) & 0xFF;
+
+ memcpy(data, ts_recent_add.ts, SIZE_TIME_STAMP);
+ data += SIZE_TIME_STAMP;
+
+ memcpy(data, ts_recent_erase.ts, SIZE_TIME_STAMP);
+ data += SIZE_TIME_STAMP;
+
+ *data++ = 0x02; // Operations supported
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_rsv_sdr (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ int rsv_id; // SDR reservation ID
+
+ // Use platform APIs to get a SDR reservation ID
+ rsv_id = sdr_rsv_id ();
+ if (rsv_id < 0)
+ {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = rsv_id & 0xFF; // Reservation ID
+ *data++ = (rsv_id >> 8) & 0XFF;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_get_sdr (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ int read_rec_id; //record ID to be read
+ int next_rec_id; //record ID for the next entry
+ int rsv_id; // Reservation ID for the request
+ int rec_offset; // Read offset into the record
+ int rec_bytes; // Number of bytes to be read
+ sdr_rec_t entry; // SDR record entry
+ int ret;
+
+ rsv_id = (req->data[1] >> 8) | req->data[0];
+ read_rec_id = (req->data[3] >> 8) | req->data[2];
+ rec_offset = req->data[4];
+ rec_bytes = req->data[5];
+
+ // Use platform API to read the record Id and get next ID
+ ret = sdr_get_entry (rsv_id, read_rec_id, &entry, &next_rec_id);
+ if (ret)
+ {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = next_rec_id & 0xFF; // next record ID
+ *data++ = (next_rec_id >> 8) & 0xFF;
+
+ memcpy (data, &entry.rec[rec_offset], rec_bytes);
+ data += rec_bytes;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_get_sel_info (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ int num_entries; // number of log entries
+ int free_space; // free space in SEL device in bytes
+ time_stamp_t ts_recent_add; // Recent Addition Timestamp
+ time_stamp_t ts_recent_erase; // Recent Erasure Timestamp
+
+ // Use platform APIs to get SEL information
+ num_entries = sel_num_entries ();
+ free_space = sel_free_space ();
+ sel_ts_recent_add (&ts_recent_add);
+ sel_ts_recent_erase (&ts_recent_erase);
+
+ res->cc = CC_SUCCESS;
+
+ *data++ = IPMI_SEL_VERSION; // SEL version
+ *data++ = num_entries & 0xFF; // number of log entries
+ *data++ = (num_entries >> 8) & 0xFF;
+ *data++ = free_space & 0xFF; // Free SEL Space
+ *data++ = (free_space >> 8) & 0xFF;
+
+ memcpy(data, ts_recent_add.ts, SIZE_TIME_STAMP);
+ data += SIZE_TIME_STAMP;
+
+ memcpy(data, ts_recent_erase.ts, SIZE_TIME_STAMP);
+ data += SIZE_TIME_STAMP;
+
+ *data++ = 0x02; // Operations supported
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_rsv_sel (unsigned char *response, unsigned char *res_len)
+{
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ int rsv_id; // SEL reservation ID
+
+ // Use platform APIs to get a SEL reservation ID
+ rsv_id = sel_rsv_id ();
+ if (rsv_id < 0)
+ {
+ res->cc = CC_SEL_ERASE_PROG;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = rsv_id & 0xFF; // Reservation ID
+ *data++ = (rsv_id >> 8) & 0XFF;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_get_sel (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ int read_rec_id; //record ID to be read
+ int next_rec_id; //record ID for the next msg
+ sel_msg_t entry; // SEL log entry
+ int ret;
+
+ read_rec_id = (req->data[3] >> 8) | req->data[2];
+
+ // Use platform API to read the record Id and get next ID
+ ret = sel_get_entry (read_rec_id, &entry, &next_rec_id);
+ if (ret)
+ {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = next_rec_id & 0xFF; // next record ID
+ *data++ = (next_rec_id >> 8) & 0xFF;
+
+ memcpy(data, entry.msg, SIZE_SEL_REC);
+ data += SIZE_SEL_REC;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_add_sel (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+
+ int record_id; // Record ID for added entry
+ int ret;
+
+ sel_msg_t entry;
+
+ memcpy(entry.msg, req->data, SIZE_SEL_REC);
+
+ // Use platform APIs to add the new SEL entry
+ ret = sel_add_entry (&entry, &record_id);
+ if (ret)
+ {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = record_id & 0xFF;
+ *data++ = (record_id >> 8) & 0xFF;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+storage_clr_sel (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+
+ sel_erase_stat_t status;
+ int ret;
+ int rsv_id;
+
+ // Verify the request to contain 'CLR' characters
+ if ((req->data[2] != 'C') || (req->data[3] != 'L') || (req->data[4] != 'R'))
+ {
+ res->cc = CC_INVALID_PARAM;
+ return;
+ }
+
+ // Populate reservation ID given in request
+ rsv_id = (req->data[1] << 8) | req->data[0];
+
+ // Use platform APIs to clear or get status
+ if (req->data[5] == IPMI_SEL_INIT_ERASE)
+ {
+ ret = sel_erase (rsv_id);
+ }
+ else if (req->data[5] == IPMI_SEL_ERASE_STAT)
+ {
+ ret = sel_erase_status (rsv_id, &status);
+ }
+ else
+ {
+ res->cc = CC_INVALID_PARAM;
+ return;
+ }
+
+ // Handle platform error and return
+ if (ret)
+ {
+ res->cc = CC_UNSPECIFIED_ERROR;
+ return;
+ }
+
+ res->cc = CC_SUCCESS;
+ *data++ = status;
+
+ *res_len = data - &res->data[0];
+
+ return;
+}
+
+static void
+ipmi_handle_storage (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char cmd = req->cmd;
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+
+ pthread_mutex_lock(&m_storage);
+ switch (cmd)
+ {
+ case CMD_STORAGE_GET_FRUID_INFO:
+ storage_get_fruid_info (response, res_len);
+ break;
+ case CMD_STORAGE_READ_FRUID_DATA:
+ storage_get_fruid_data (request, response, res_len);
+ break;
+ case CMD_STORAGE_GET_SEL_INFO:
+ storage_get_sel_info (response, res_len);
+ break;
+ case CMD_STORAGE_RSV_SEL:
+ storage_rsv_sel (response, res_len);
+ break;
+ case CMD_STORAGE_ADD_SEL:
+ storage_add_sel (request, response, res_len);
+ break;
+ case CMD_STORAGE_GET_SEL:
+ storage_get_sel (request, response, res_len);
+ break;
+ case CMD_STORAGE_CLR_SEL:
+ storage_clr_sel (request, response, res_len);
+ break;
+ case CMD_STORAGE_GET_SDR_INFO:
+ storage_get_sdr_info (response, res_len);
+ break;
+ case CMD_STORAGE_RSV_SDR:
+ storage_rsv_sdr (response, res_len);
+ break;
+ case CMD_STORAGE_GET_SDR:
+ storage_get_sdr (request, response, res_len);
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ break;
+ }
+
+ pthread_mutex_unlock(&m_storage);
+ return;
+}
+
+/*
+ * Function(s) to handle IPMI messages with NetFn: Transport
+ */
+
+// Set LAN Configuration (IPMI/Section 23.1)
+static void
+transport_set_lan_config (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char param = req->data[1];
+
+ // Fill the response with default values
+ res->cc = CC_SUCCESS;
+
+ switch (param)
+ {
+ case LAN_PARAM_SET_IN_PROG:
+ g_lan_config.set_in_prog = req->data[2];
+ break;
+ case LAN_PARAM_AUTH_SUPPORT:
+ g_lan_config.auth_support = req->data[2];
+ break;
+ case LAN_PARAM_AUTH_ENABLES:
+ memcpy(g_lan_config.auth_enables, &req->data[2], SIZE_AUTH_ENABLES);
+ break;
+ case LAN_PARAM_IP_ADDR:
+ memcpy(g_lan_config.ip_addr, &req->data[2], SIZE_IP_ADDR);
+ break;
+ case LAN_PARAM_IP_SRC:
+ g_lan_config.ip_src = req->data[2];
+ break;
+ case LAN_PARAM_MAC_ADDR:
+ memcpy(g_lan_config.mac_addr, &req->data[2], SIZE_MAC_ADDR);
+ break;
+ case LAN_PARAM_NET_MASK:
+ memcpy(g_lan_config.net_mask, &req->data[2], SIZE_NET_MASK);
+ break;
+ case LAN_PARAM_IP_HDR:
+ memcpy(g_lan_config.ip_hdr, &req->data[2], SIZE_IP_HDR);
+ break;
+ case LAN_PARAM_PRI_RMCP_PORT:
+ g_lan_config.pri_rmcp_port[0] = req->data[2];
+ g_lan_config.pri_rmcp_port[1] = req->data[3];
+ break;
+ case LAN_PARAM_SEC_RMCP_PORT:
+ g_lan_config.sec_rmcp_port[0] = req->data[2];
+ g_lan_config.sec_rmcp_port[1] = req->data[3];
+ break;
+ case LAN_PARAM_ARP_CTRL:
+ g_lan_config.arp_ctrl = req->data[2];
+ break;
+ case LAN_PARAM_GARP_INTERVAL:
+ g_lan_config.garp_interval = req->data[2];
+ break;
+ case LAN_PARAM_DF_GW_IP_ADDR:
+ memcpy(g_lan_config.df_gw_ip_addr, &req->data[2], SIZE_IP_ADDR);
+ break;
+ case LAN_PARAM_DF_GW_MAC_ADDR:
+ memcpy(g_lan_config.df_gw_mac_addr, &req->data[2], SIZE_MAC_ADDR);
+ break;
+ case LAN_PARAM_BACK_GW_IP_ADDR:
+ memcpy(g_lan_config.back_gw_ip_addr, &req->data[2], SIZE_IP_ADDR);
+ break;
+ case LAN_PARAM_BACK_GW_MAC_ADDR:
+ memcpy(g_lan_config.back_gw_mac_addr, &req->data[2], SIZE_MAC_ADDR);
+ break;
+ case LAN_PARAM_COMMUNITY_STR:
+ memcpy(g_lan_config.community_str, &req->data[2], SIZE_COMMUNITY_STR);
+ break;
+ case LAN_PARAM_NO_OF_DEST:
+ g_lan_config.no_of_dest = req->data[2];
+ break;
+ case LAN_PARAM_DEST_TYPE:
+ memcpy(g_lan_config.dest_type, &req->data[2], SIZE_DEST_TYPE);
+ break;
+ case LAN_PARAM_DEST_ADDR:
+ memcpy(g_lan_config.dest_addr, &req->data[2], SIZE_DEST_ADDR);
+ break;
+ default:
+ res->cc = CC_INVALID_PARAM;
+ break;
+ }
+}
+
+// Get LAN Configuration (IPMI/Section 23.2)
+static void
+transport_get_lan_config (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char *data = &res->data[0];
+ unsigned char param = req->data[1];
+
+ // Fill the response with default values
+ res->cc = CC_SUCCESS;
+ *data++ = 0x01; // Parameter revision
+
+ switch (param)
+ {
+ case LAN_PARAM_SET_IN_PROG:
+ *data++ = g_lan_config.set_in_prog;
+ break;
+ case LAN_PARAM_AUTH_SUPPORT:
+ *data++ = g_lan_config.auth_support;
+ break;
+ case LAN_PARAM_AUTH_ENABLES:
+ memcpy(data, g_lan_config.auth_enables, SIZE_AUTH_ENABLES);
+ data += SIZE_AUTH_ENABLES;
+ break;
+ case LAN_PARAM_IP_ADDR:
+ memcpy(data, g_lan_config.ip_addr, SIZE_IP_ADDR);
+ data += SIZE_IP_ADDR;
+ break;
+ case LAN_PARAM_IP_SRC:
+ *data++ = g_lan_config.ip_src;
+ break;
+ case LAN_PARAM_MAC_ADDR:
+ memcpy(data, g_lan_config.mac_addr, SIZE_MAC_ADDR);
+ data += SIZE_MAC_ADDR;
+ break;
+ case LAN_PARAM_NET_MASK:
+ memcpy(data, g_lan_config.net_mask, SIZE_NET_MASK);
+ data += SIZE_NET_MASK;
+ break;
+ case LAN_PARAM_IP_HDR:
+ memcpy(data, g_lan_config.ip_hdr, SIZE_IP_HDR);
+ data += SIZE_IP_HDR;
+ break;
+ case LAN_PARAM_PRI_RMCP_PORT:
+ *data++ = g_lan_config.pri_rmcp_port[0];
+ *data++ = g_lan_config.pri_rmcp_port[1];
+ break;
+ case LAN_PARAM_SEC_RMCP_PORT:
+ *data++ = g_lan_config.sec_rmcp_port[0];
+ *data++ = g_lan_config.sec_rmcp_port[1];
+ break;
+ case LAN_PARAM_ARP_CTRL:
+ *data++ = g_lan_config.arp_ctrl;
+ break;
+ case LAN_PARAM_GARP_INTERVAL:
+ *data++ = g_lan_config.garp_interval;
+ break;
+ case LAN_PARAM_DF_GW_IP_ADDR:
+ memcpy(data, g_lan_config.df_gw_ip_addr, SIZE_IP_ADDR);
+ data += SIZE_IP_ADDR;
+ break;
+ case LAN_PARAM_DF_GW_MAC_ADDR:
+ memcpy(data, g_lan_config.df_gw_mac_addr, SIZE_MAC_ADDR);
+ data += SIZE_MAC_ADDR;
+ break;
+ case LAN_PARAM_BACK_GW_IP_ADDR:
+ memcpy(data, g_lan_config.back_gw_ip_addr, SIZE_IP_ADDR);
+ data += SIZE_IP_ADDR;
+ break;
+ case LAN_PARAM_BACK_GW_MAC_ADDR:
+ memcpy(data, g_lan_config.back_gw_mac_addr, SIZE_MAC_ADDR);
+ data += SIZE_MAC_ADDR;
+ break;
+ case LAN_PARAM_COMMUNITY_STR:
+ memcpy(data, g_lan_config.community_str, SIZE_COMMUNITY_STR);
+ data += SIZE_COMMUNITY_STR;
+ break;
+ case LAN_PARAM_NO_OF_DEST:
+ *data++ = g_lan_config.no_of_dest;
+ break;
+ case LAN_PARAM_DEST_TYPE:
+ memcpy(data, g_lan_config.dest_type, SIZE_DEST_TYPE);
+ data += SIZE_DEST_TYPE;
+ break;
+ case LAN_PARAM_DEST_ADDR:
+ memcpy(data, g_lan_config.dest_addr, SIZE_DEST_ADDR);
+ data += SIZE_DEST_ADDR;
+ break;
+ default:
+ res->cc = CC_INVALID_PARAM;
+ break;
+ }
+
+ if (res->cc == CC_SUCCESS) {
+ *res_len = data - &res->data[0];
+ }
+}
+
+// Handle Transport Commands (IPMI/Section 23)
+static void
+ipmi_handle_transport (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char cmd = req->cmd;
+
+ pthread_mutex_lock(&m_transport);
+ switch (cmd)
+ {
+ case CMD_TRANSPORT_SET_LAN_CONFIG:
+ transport_set_lan_config (request, response, res_len);
+ break;
+ case CMD_TRANSPORT_GET_LAN_CONFIG:
+ transport_get_lan_config (request, response, res_len);
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ break;
+ }
+ pthread_mutex_unlock(&m_transport);
+}
+
+/*
+ * Function(s) to handle IPMI messages with NetFn: OEM
+ */
+
+static void
+oem_set_proc_info (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ g_proc_info.type = req->data[1];
+ g_proc_info.freq[0] = req->data[2];
+ g_proc_info.freq[1] = req->data[3];
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+}
+
+static void
+oem_set_dimm_info (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ unsigned char index = req->data[0];
+
+ g_dimm_info[index].type = req->data[1];
+ g_dimm_info[index].speed[0] = req->data[2];
+ g_dimm_info[index].speed[1] = req->data[3];
+ g_dimm_info[index].size[0] = req->data[4];
+ g_dimm_info[index].size[1] = req->data[5];
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+}
+
+static void
+oem_set_post_start (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ // TODO: For now logging the event, need to find usage for this info
+ syslog (LOG_INFO, "POST Start Event for Payload#%d\n", req->payload_id);
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+}
+
+static void
+oem_set_post_end (unsigned char *request, unsigned char *response,
+ unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ // TODO: For now logging the event, need to find usage for this info
+ syslog (LOG_INFO, "POST End Event for Payload#%d\n", req->payload_id);
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+}
+
+static void
+ipmi_handle_oem (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ unsigned char cmd = req->cmd;
+
+ pthread_mutex_lock(&m_oem);
+ switch (cmd)
+ {
+ case CMD_OEM_SET_PROC_INFO:
+ oem_set_proc_info (request, response, res_len);
+ break;
+ case CMD_OEM_SET_DIMM_INFO:
+ oem_set_dimm_info (request, response, res_len);
+ break;
+ case CMD_OEM_SET_POST_START:
+ oem_set_post_start (request, response, res_len);
+ break;
+ case CMD_OEM_SET_POST_END:
+ oem_set_post_end (request, response, res_len);
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ break;
+ }
+ pthread_mutex_unlock(&m_oem);
+}
+
+static void
+oem_1s_handle_ipmb_kcs(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ // Need to extract bridged IPMI command and handle
+ unsigned char req_buf[MAX_IPMI_MSG_SIZE] = {0};
+ unsigned char res_buf[MAX_IPMI_MSG_SIZE] = {0};
+
+ // Add the payload id from the bridged command
+ req_buf[0] = req->payload_id;
+
+ // Remove OEM IPMI Header + 1 byte for BIC interface
+ // The offset moves by one due to the payload ID
+ memcpy(&req_buf[1], &request[BIC_INTF_HDR_SIZE + 1], req_len - BIC_INTF_HDR_SIZE);
+
+ // Send the bridged KCS command along with the payload ID
+ // The offset moves by one due to the payload ID
+ ipmi_handle(req_buf, req_len - BIC_INTF_HDR_SIZE + 1, res_buf, res_len);
+
+ // Copy the response back
+ memcpy(&res->data[1], res_buf, *res_len);
+
+ // Add the OEM command's response
+ res->cc = CC_SUCCESS;
+ res->data[0] = req->data[0]; // Bridge-IC interface
+ *res_len += 1;
+}
+
+static void
+oem_1s_handle_ipmb_req(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+
+ // handle based on Bridge-IC interface
+ switch(req->data[0]) {
+ case BIC_INTF_ME:
+ // TODO: Need to call ME command handler
+ syslog(LOG_INFO, "oem_1s_handle_ipmb_req: Command received from ME for "
+ "payload#%d\n", req->payload_id);
+ res->data[0] = BIC_INTF_ME;
+ res->cc = CC_SUCCESS;
+ *res_len = 1;
+ break;
+ case BIC_INTF_SOL:
+ // TODO: Need to call Optional SoL message handler
+ syslog(LOG_INFO, "oem_1s_handle_ipmb_req: Command received from SOL for "
+ "payload#%d\n", req->payload_id);
+ res->data[0] = BIC_INTF_SOL;
+ res->cc = CC_SUCCESS;
+ *res_len = 1;
+ break;
+ case BIC_INTF_KCS:
+ oem_1s_handle_ipmb_kcs(request, req_len, response, res_len);
+ break;
+ default:
+ // TODO: Need to add additonal interface handler, if supported
+ syslog(LOG_ALERT, "oem_1s_handle_ipmb_req: Command received on intf#%d "
+ "for payload#%d", req->data[0], req->payload_id);
+ res->cc = CC_INVALID_PARAM;
+ *res_len = 0;
+ break;
+ }
+}
+
+static void
+ipmi_handle_oem_1s(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ int i;
+
+ unsigned char cmd = req->cmd;
+
+ pthread_mutex_lock(&m_oem_1s);
+ switch (cmd)
+ {
+ case CMD_OEM_1S_MSG_IN:
+ oem_1s_handle_ipmb_req(request, req_len, response, res_len);
+ break;
+ case CMD_OEM_1S_INTR:
+ syslog(LOG_INFO, "ipmi_handle_oem_1s: 1S server interrupt#%d received "
+ "for payload#%d\n", req->data[0], req->payload_id);
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+ break;
+ case CMD_OEM_1S_POST_BUF:
+ for (i = 1; i <= req->data[0]; i++) {
+ pal_post_handle(req->payload_id, req->data[i]);
+ }
+
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+ break;
+ case CMD_OEM_1S_PLAT_DISC:
+ syslog(LOG_INFO, "ipmi_handle_oem_1s: Platform Discovery received for "
+ "payload#%d\n", req->payload_id);
+ res->cc = CC_SUCCESS;
+ *res_len = 0;
+ break;
+ case CMD_OEM_1S_BIC_RESET:
+ syslog(LOG_INFO, "ipmi_handle_oem_1s: BIC Reset received "
+ "for payload#%d\n", req->payload_id);
+
+ if (req->data[0] == 0x0) {
+ syslog(LOG_ALERT, "Cold Reset by Firmware Update\n");
+ res->cc = CC_SUCCESS;
+ } else if (req->data[1] == 0x01) {
+ syslog(LOG_ALERT, "WDT Reset\n");
+ res->cc = CC_SUCCESS;
+ } else {
+ syslog(LOG_ALERT, "Error\n");
+ res->cc = CC_INVALID_PARAM;
+ }
+
+ *res_len = 0;
+ break;
+ case CMD_OEM_1S_BIC_UPDATE_MODE:
+ syslog(LOG_INFO, "ipmi_handle_oem_1s: BIC Update Mode received "
+ "for payload#%d\n", req->payload_id);
+
+ if (req->data[0] == 0x0) {
+ syslog(LOG_INFO, "Normal Mode\n");
+ res->cc = CC_SUCCESS;
+ } else if (req->data[1] == 0x0F) {
+ syslog(LOG_INFO, "Update Mode\n");
+ res->cc = CC_SUCCESS;
+ } else {
+ syslog(LOG_ALERT, "Error\n");
+ res->cc = CC_INVALID_PARAM;
+ }
+
+ *res_len = 0;
+ break;
+ default:
+ res->cc = CC_INVALID_CMD;
+ *res_len = 0;
+ break;
+ }
+ pthread_mutex_unlock(&m_oem_1s);
+}
+
+/*
+ * Function to handle all IPMI messages
+ */
+static void
+ipmi_handle (unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+
+ ipmi_mn_req_t *req = (ipmi_mn_req_t *) request;
+ ipmi_res_t *res = (ipmi_res_t *) response;
+ unsigned char netfn;
+
+ netfn = req->netfn_lun >> 2;
+
+ // Provide default values in the response message
+ res->cmd = req->cmd;
+ res->cc = 0xFF; // Unspecified completion code
+ *res_len = 0;
+
+ switch (netfn)
+ {
+ case NETFN_CHASSIS_REQ:
+ res->netfn_lun = NETFN_CHASSIS_RES << 2;
+ ipmi_handle_chassis (request, req_len, response, res_len);
+ break;
+ case NETFN_APP_REQ:
+ res->netfn_lun = NETFN_APP_RES << 2;
+ ipmi_handle_app (request, req_len, response, res_len);
+ break;
+ case NETFN_STORAGE_REQ:
+ res->netfn_lun = NETFN_STORAGE_RES << 2;
+ ipmi_handle_storage (request, req_len, response, res_len);
+ break;
+ case NETFN_TRANSPORT_REQ:
+ res->netfn_lun = NETFN_TRANSPORT_RES << 2;
+ ipmi_handle_transport (request, req_len, response, res_len);
+ break;
+ case NETFN_OEM_REQ:
+ res->netfn_lun = NETFN_OEM_RES << 2;
+ ipmi_handle_oem (request, req_len, response, res_len);
+ break;
+ case NETFN_OEM_1S_REQ:
+ res->netfn_lun = NETFN_OEM_1S_RES << 2;
+ ipmi_handle_oem_1s(request, req_len, response, res_len);
+ break;
+ default:
+ res->netfn_lun = (netfn + 1) << 2;
+ break;
+ }
+
+ // This header includes NetFunction, Command, and Completion Code
+ *res_len += IPMI_RESP_HDR_SIZE;
+
+ return;
+}
+
+void
+*conn_handler(void *socket_desc) {
+ int sock = *(int*)socket_desc;
+ int n;
+ unsigned char req_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_len = 0;
+
+ n = recv (sock, req_buf, sizeof(req_buf), 0);
+ if (n <= 0) {
+ syslog(LOG_ALERT, "ipmid: recv() failed with %d\n", n);
+ goto conn_cleanup;
+ }
+
+ ipmi_handle(req_buf, n, res_buf, &res_len);
+
+ if (send (sock, res_buf, res_len, 0) < 0) {
+ syslog(LOG_ALERT, "ipmid: send() failed\n");
+ }
+
+conn_cleanup:
+ close(sock);
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+
+int
+main (void)
+{
+ int s, s2, t, len;
+ struct sockaddr_un local, remote;
+ pthread_t tid;
+
+ daemon(1, 0);
+ openlog("ipmid", LOG_CONS, LOG_DAEMON);
+
+
+ plat_fruid_init();
+ plat_sensor_init();
+
+ sdr_init();
+ sel_init();
+
+ pthread_mutex_init(&m_chassis, NULL);
+ pthread_mutex_init(&m_app, NULL);
+ pthread_mutex_init(&m_storage, NULL);
+ pthread_mutex_init(&m_transport, NULL);
+ pthread_mutex_init(&m_oem, NULL);
+ pthread_mutex_init(&m_oem_1s, NULL);
+
+ if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ syslog(LOG_ALERT, "ipmid: socket() failed\n");
+ exit (1);
+ }
+
+ local.sun_family = AF_UNIX;
+ strcpy (local.sun_path, SOCK_PATH_IPMI);
+ unlink (local.sun_path);
+ len = strlen (local.sun_path) + sizeof (local.sun_family);
+ if (bind (s, (struct sockaddr *) &local, len) == -1)
+ {
+ syslog(LOG_ALERT, "ipmid: bind() failed\n");
+ exit (1);
+ }
+
+ if (listen (s, 5) == -1)
+ {
+ syslog(LOG_ALERT, "ipmid: listen() failed\n");
+ exit (1);
+ }
+
+ while(1) {
+ int n;
+ t = sizeof (remote);
+ if ((s2 = accept (s, (struct sockaddr *) &remote, &t)) < 0) {
+ syslog(LOG_ALERT, "ipmid: accept() failed\n");
+ break;
+ }
+
+ // Creating a worker thread to handle the request
+ // TODO: Need to monitor the server performance with higher load and
+ // see if we need to create pre-defined number of workers and schedule
+ // the requests among them.
+ if (pthread_create(&tid, NULL, conn_handler, (void*) &s2) < 0) {
+ syslog(LOG_ALERT, "ipmid: pthread_create failed\n");
+ close(s2);
+ continue;
+ }
+
+ pthread_detach(tid);
+ }
+
+ close(s);
+
+ pthread_mutex_destroy(&m_chassis);
+ pthread_mutex_destroy(&m_app);
+ pthread_mutex_destroy(&m_storage);
+ pthread_mutex_destroy(&m_transport);
+ pthread_mutex_destroy(&m_oem);
+ pthread_mutex_destroy(&m_oem_1s);
+
+ return 0;
+}
diff --git a/common/recipes-core/ipmid/files/sdr.c b/common/recipes-core/ipmid/files/sdr.c
new file mode 100644
index 0000000..91a4df5
--- /dev/null
+++ b/common/recipes-core/ipmid/files/sdr.c
@@ -0,0 +1,414 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This file represents platform specific implementation for storing
+ * SDR record entries and acts as back-end for IPMI stack
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "sdr.h"
+#include "sensor.h"
+#include "timestamp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <openbmc/ipmi.h>
+
+// SDR Header magic number
+#define SDR_HDR_MAGIC 0xFBFBFBFB
+
+// SDR Header version number
+#define SDR_HDR_VERSION 0x01
+
+// SDR reservation IDs can not be 0x00 or 0xFFFF
+#define SDR_RSVID_MIN 0x01
+#define SDR_RSVID_MAX 0xFFFE
+
+#define SDR_RECORDS_MAX 64 // to support around 64 sensors
+
+// SDR index to keep track
+#define SDR_INDEX_MIN 0
+#define SDR_INDEX_MAX (SDR_RECORDS_MAX - 1)
+
+// Record ID can not be 0x0 (IPMI/Section 31)
+#define SDR_RECID_MIN 1
+#define SDR_RECID_MAX SDR_RECORDS_MAX
+
+// Special RecID value for first and last (IPMI/Section 31)
+#define SDR_RECID_FIRST 0x0000
+#define SDR_RECID_LAST 0xFFFF
+
+#define SDR_VERSION 0x51
+#define SDR_LEN_MAX 64
+
+#define SDR_FULL_TYPE 0x01
+#define SDR_MGMT_TYPE 0x12
+#define SDR_OEM_TYPE 0xC0
+
+#define SDR_FULL_LEN 64
+#define SDR_MGMT_LEN 32
+#define SDR_OEM_LEN 64
+
+// SDR header struct to keep track of SEL Log entries
+typedef struct {
+ int magic; // Magic number to check validity
+ int version; // version number of this header
+ int begin; // index to the first SDR entry
+ int end; // index to the last SDR entry
+ time_stamp_t ts_add; // last addition time stamp
+ time_stamp_t ts_erase; // last erase time stamp
+} sdr_hdr_t;
+
+// Keep track of last Reservation ID
+static int g_rsv_id = 0x01;
+
+// SDR Header and data global structures
+static sdr_hdr_t g_sdr_hdr;
+static sdr_rec_t g_sdr_data[SDR_RECORDS_MAX];
+
+// Add a new SDR entry
+static int
+sdr_add_entry(sdr_rec_t *rec, int *rec_id) {
+ // If SDR is full, return error
+ if (sdr_num_entries() == SDR_RECORDS_MAX) {
+ syslog(LOG_ALERT, "sdr_add_entry: SDR full\n");
+ return -1;
+ }
+
+ // Add Record ID which is array index + 1
+ rec->rec[0] = g_sdr_hdr.end+1;
+
+ // Add the enry at end
+ memcpy(g_sdr_data[g_sdr_hdr.end].rec, rec->rec, sizeof(sdr_rec_t));
+
+ // Return the newly added record ID
+ *rec_id = g_sdr_hdr.end+1;
+
+ // Increment the end pointer
+ ++g_sdr_hdr.end;
+
+ // Update timestamp for add in header
+ time_stamp_fill(g_sdr_hdr.ts_add.ts);
+
+ return 0;
+}
+
+static int
+sdr_add_mgmt_rec(sensor_mgmt_t *p_rec) {
+ int rec_id = 0;
+ sdr_rec_t sdr = { 0 };
+ sdr_mgmt_t rec = { 0 };
+
+ // Populate SDR MGMT record
+ rec.ver = SDR_VERSION;
+ rec.type = SDR_MGMT_TYPE;
+ rec.len = SDR_MGMT_LEN;
+
+ rec.slave_addr = p_rec->slave_addr;
+ rec.chan_no = p_rec->chan_no;
+
+ rec.pwr_state_init = p_rec->pwr_state_init;
+ rec.dev_caps = p_rec->dev_caps;
+ rec.ent_id = p_rec->ent_id;
+ rec.ent_inst = p_rec->ent_inst;
+ rec.oem = p_rec->oem;
+ rec.str_type_len = p_rec->str_type_len;
+ memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE);
+
+ // Copy this record to generic SDR record
+ memcpy(sdr.rec, &rec, SDR_LEN_MAX);
+
+ // Add this record to SDR repo
+ if (sdr_add_entry(&sdr, &rec_id)) {
+ syslog(LOG_ALERT, "sdr_add_mgmt_rec: sdr_add_entry failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+sdr_add_disc_rec(sensor_disc_t *p_rec) {
+ int rec_id = 0;
+ sdr_rec_t sdr = { 0 };
+ sdr_full_t rec = { 0 };
+
+ // Populate SDR FULL record
+ rec.ver = SDR_VERSION;
+ rec.type = SDR_FULL_TYPE;
+ rec.len = SDR_FULL_LEN;
+
+ rec.owner = p_rec->owner;
+ rec.lun = p_rec->lun;
+
+ rec.ent_id = p_rec->ent_id;
+ rec.ent_inst = p_rec->ent_inst;
+ rec.sensor_init = p_rec->sensor_init;
+ rec.sensor_caps = p_rec->sensor_caps;
+ rec.sensor_type = p_rec->sensor_type;
+ rec.evt_read_type = p_rec->evt_read_type;
+ memcpy(rec.assert_evt_mask, p_rec->assert_evt_mask, 2);
+ memcpy(rec.deassert_evt_mask, p_rec->deassert_evt_mask, 2);
+ memcpy(rec.read_evt_mask, p_rec->read_evt_mask, 2);
+ rec.oem = p_rec->oem;
+ rec.str_type_len = p_rec->str_type_len;
+ memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE);
+
+ // Copy this record to generic SDR record
+ memcpy(sdr.rec, &rec, SDR_LEN_MAX);
+
+ // Add this record to SDR repo
+ if (sdr_add_entry(&sdr, &rec_id)) {
+ syslog(LOG_ALERT, "sdr_add_disc_rec: sdr_add_entry failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+sdr_add_thresh_rec(sensor_thresh_t *p_rec) {
+ int rec_id = 0;
+ sdr_rec_t sdr = { 0 };
+ sdr_full_t rec = { 0 };
+
+ // Populate SDR FULL record
+ rec.ver = SDR_VERSION;
+ rec.type = SDR_FULL_TYPE;
+ rec.len = SDR_FULL_LEN;
+
+ rec.owner = p_rec->owner;
+ rec.lun = p_rec->lun;
+
+ rec.ent_id = p_rec->ent_id;
+ rec.ent_inst = p_rec->ent_inst;
+ rec.sensor_init = p_rec->sensor_init;
+ rec.sensor_caps = p_rec->sensor_caps;
+ rec.sensor_type = p_rec->sensor_type;
+ rec.evt_read_type = p_rec->evt_read_type;
+ memcpy(rec.lt_read_mask, p_rec->lt_read_mask, 2);
+ memcpy(rec.ut_read_mask, p_rec->ut_read_mask, 2);
+ memcpy(rec.set_thresh_mask, p_rec->set_thresh_mask, 2);
+ rec.sensor_units1 = p_rec->sensor_units1;
+ rec.sensor_units2 = p_rec->sensor_units2;
+ rec.sensor_units3 = p_rec->sensor_units3;
+ rec.linear = p_rec->linear;
+ rec.m_val = p_rec->m_val;
+ rec.m_tolerance = p_rec->m_tolerance;
+ rec.b_val = p_rec->b_val;
+ rec.b_accuracy = p_rec->b_accuracy;
+ rec.analog_flags = p_rec->analog_flags;
+ rec.nominal = p_rec->nominal;
+ rec.normal_max = p_rec->normal_max;
+ rec.normal_min = p_rec->normal_min;
+ rec.max_reading = p_rec->max_reading;
+ rec.min_reading = p_rec->min_reading;
+ rec.unr_thresh = p_rec->unr_thresh;
+ rec.uc_thresh = p_rec->uc_thresh;
+ rec.unc_thresh = p_rec->unc_thresh;
+ rec.lnr_thresh = p_rec->lnr_thresh;
+ rec.lc_thresh = p_rec->lc_thresh;
+ rec.lnc_thresh = p_rec->lnc_thresh;
+ rec.pos_hyst = p_rec->pos_hyst;
+ rec.neg_hyst = p_rec->neg_hyst;
+ rec.oem = p_rec->oem;
+ rec.str_type_len = p_rec->str_type_len;
+ memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE);
+
+ // Copy this record to generic SDR record
+ memcpy(sdr.rec, &rec, SDR_LEN_MAX);
+
+ // Add this record to SDR repo
+ if (sdr_add_entry(&sdr, &rec_id)) {
+ syslog(LOG_ALERT, "sdr_add_thresh_rec: sdr_add_entry failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+sdr_add_oem_rec(sensor_oem_t *p_rec) {
+ int rec_id = 0;
+ sdr_rec_t sdr = { 0 };
+ sdr_oem_t rec = { 0 };
+
+ // Populate SDR OEM record
+ rec.ver = SDR_VERSION;
+ rec.type = SDR_OEM_TYPE;
+ rec.len = SDR_OEM_LEN;
+
+ memcpy(rec.mfr_id, p_rec->mfr_id, 3);
+ memcpy(rec.oem_data, p_rec->oem_data, SENSOR_OEM_DATA_SIZE);
+
+ // Copy this record to generic SDR record
+ memcpy(sdr.rec, &rec, SDR_LEN_MAX);
+
+ // Add this record to SDR repo
+ if (sdr_add_entry(&sdr, &rec_id)) {
+ syslog(LOG_ALERT, "sdr_add_oem_rec: sdr_add_entry failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+// Platform specific SEL API entry points
+// Retrieve time stamp for recent add operation
+void
+sdr_ts_recent_add(time_stamp_t *ts) {
+ memcpy(ts->ts, g_sdr_hdr.ts_add.ts, 0x04);
+}
+
+// Retrieve time stamp for recent erase operation
+void
+sdr_ts_recent_erase(time_stamp_t *ts) {
+ memcpy(ts->ts, g_sdr_hdr.ts_erase.ts, 0x04);
+}
+
+// Retrieve total number of entries in SDR repo
+int
+sdr_num_entries(void) {
+ return (g_sdr_hdr.end - g_sdr_hdr.begin);
+}
+
+// Retrieve total free space available in SDR repo
+int
+sdr_free_space(void) {
+ int total_space;
+ int used_space;
+
+ total_space = SDR_RECORDS_MAX * sizeof(sdr_rec_t);
+ used_space = sdr_num_entries() * sizeof(sdr_rec_t);
+
+ return (total_space - used_space);
+}
+
+// Reserve an ID that will be used in later operations
+// IPMI/Section 33.11
+int
+sdr_rsv_id() {
+ // Increment the current reservation ID and return
+ if (g_rsv_id++ == SDR_RSVID_MAX) {
+ g_rsv_id = SDR_RSVID_MIN;
+ }
+
+ return g_rsv_id;
+}
+
+// Get the SDR entry for a given record ID
+// IPMI/Section 33.12
+int
+sdr_get_entry(int rsv_id, int read_rec_id, sdr_rec_t *rec,
+ int *next_rec_id) {
+
+ int index;
+
+ // Make sure the rsv_id matches
+ if (rsv_id != g_rsv_id) {
+ syslog(LOG_ALERT, "sdr_get_entry: Reservation ID mismatch\n");
+ return -1;
+ }
+
+ // Find the index in to array based on given index
+ if (read_rec_id == SDR_RECID_FIRST) {
+ index = g_sdr_hdr.begin;
+ } else if (read_rec_id == SDR_RECID_LAST) {
+ index = g_sdr_hdr.end - 1;
+ } else {
+ index = read_rec_id - 1;
+ }
+
+ // If the SDR repo is empty return error
+ if (sdr_num_entries() == 0) {
+ syslog(LOG_ALERT, "sdr_get_entry: No entries\n");
+ return -1;
+ }
+
+ // Check for boundary conditions
+ if ((index < SDR_INDEX_MIN) || (index > SDR_INDEX_MAX)) {
+ syslog(LOG_ALERT, "sdr_get_entry: Invalid Record ID %d\n", read_rec_id);
+ return -1;
+ }
+
+ // Check to make sure the given id is valid
+ if (index < g_sdr_hdr.begin || index >= g_sdr_hdr.end) {
+ syslog(LOG_ALERT, "sdr_get_entry: Wrong Record ID %d\n", read_rec_id);
+ return -1;
+ }
+
+ memcpy(rec->rec, g_sdr_data[index].rec, sizeof(sdr_rec_t));
+
+ // Return the next record ID in the log
+ *next_rec_id = ++read_rec_id;
+
+ // If this is the last entry in the log, return 0xFFFF
+ if (*next_rec_id == g_sdr_hdr.end) {
+ *next_rec_id = SDR_RECID_LAST;
+ }
+
+ return 0;
+}
+
+
+// Initialize SDR Repo structure
+int
+sdr_init(void) {
+ int num;
+ int i;
+ sensor_mgmt_t *p_mgmt;
+ sensor_thresh_t *p_thresh;
+ sensor_disc_t *p_disc;
+ sensor_oem_t *p_oem;
+
+ // Populate SDR Header
+ g_sdr_hdr.magic = SDR_HDR_MAGIC;
+ g_sdr_hdr.version = SDR_HDR_VERSION;
+ g_sdr_hdr.begin = SDR_INDEX_MIN;
+ g_sdr_hdr.end = SDR_INDEX_MIN;
+ memset(g_sdr_hdr.ts_add.ts, 0x0, 4);
+ memset(g_sdr_hdr.ts_erase.ts, 0x0, 4);
+
+ // Populate all mgmt control sensors
+ plat_sensor_mgmt_info(&num, &p_mgmt);
+ for (i = 0; i < num; i++) {
+ sdr_add_mgmt_rec(&p_mgmt[i]);
+ }
+
+ // Populate all discrete sensors
+ plat_sensor_disc_info(&num, &p_disc);
+ for (i = 0; i < num; i++) {
+ sdr_add_disc_rec(&p_disc[i]);
+ }
+
+ // Populate all threshold sensors
+ plat_sensor_thresh_info(&num, &p_thresh);
+ for (i = 0; i < num; i++) {
+ sdr_add_thresh_rec(&p_thresh[i]);
+ }
+
+ // Populate all OEM sensors
+ plat_sensor_oem_info(&num, &p_oem);
+ for (i = 0; i < num; i++) {
+ sdr_add_oem_rec(&p_oem[i]);
+ }
+
+ return 0;
+}
diff --git a/common/recipes-core/ipmid/files/sdr.h b/common/recipes-core/ipmid/files/sdr.h
new file mode 100644
index 0000000..5c11c31
--- /dev/null
+++ b/common/recipes-core/ipmid/files/sdr.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SDR_H__
+#define __SDR_H__
+
+#include "timestamp.h"
+
+typedef struct {
+ unsigned char rec[64];
+} sdr_rec_t;
+
+// Mgmt. Controller SDR record; IPMI/ Section 43.9
+typedef struct {
+ // Sensor Record Header
+ unsigned char rec_id[2];
+ unsigned char ver;
+ unsigned char type;
+ unsigned char len;
+ // Record Key Bytes
+ unsigned char slave_addr;
+ unsigned char chan_no;
+ // Record Body Bytes
+ unsigned char pwr_state_init;
+ unsigned char dev_caps;
+ unsigned char rsvd[3];
+ unsigned char ent_id;
+ unsigned char ent_inst;
+ unsigned char oem;
+ unsigned char str_type_len;
+ char str[16];
+} sdr_mgmt_t;
+
+// OEM type SDR record; IPMI/Section 43.12
+typedef struct {
+ // Sensor Record Header
+ unsigned char rec_id[2];
+ unsigned char ver;
+ unsigned char type;
+ unsigned char len;
+ // Record Body Bytes
+ unsigned char mfr_id[3];
+ unsigned char oem_data[56];
+} sdr_oem_t;
+
+void sdr_ts_recent_add(time_stamp_t *ts);
+void sdr_ts_recent_erase(time_stamp_t *ts);
+int sdr_num_entries(void);
+int sdr_free_space(void);
+int sdr_rsv_id();
+int sdr_get_entry(int rsv_id, int read_rec_id, sdr_rec_t *rec,
+ int *next_rec_id);
+int sdr_init(void);
+
+#endif /* __SDR_H__ */
diff --git a/common/recipes-core/ipmid/files/sel.c b/common/recipes-core/ipmid/files/sel.c
new file mode 100644
index 0000000..d598bb1
--- /dev/null
+++ b/common/recipes-core/ipmid/files/sel.c
@@ -0,0 +1,440 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This file represents platform specific implementation for storing
+ * SEL logs and acts as back-end for IPMI stack
+ *
+ * TODO: Optimize the file handling to keep file open always instead of
+ * current open/seek/close
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "sel.h"
+#include "timestamp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+
+// SEL File.
+#define SEL_LOG_FILE "/mnt/data/sel.bin"
+
+// SEL Header magic number
+#define SEL_HDR_MAGIC 0xFBFBFBFB
+
+// SEL Header version number
+#define SEL_HDR_VERSION 0x01
+
+// SEL Data offset from file beginning
+#define SEL_DATA_OFFSET 0x100
+
+// SEL reservation IDs can not be 0x00 or 0xFFFF
+#define SEL_RSVID_MIN 0x01
+#define SEL_RSVID_MAX 0xFFFE
+
+// Number of SEL records before wrap
+#define SEL_RECORDS_MAX 128 // TODO: Based on need we can make it bigger
+#define SEL_ELEMS_MAX (SEL_RECORDS_MAX+1)
+
+// Index for circular array
+#define SEL_INDEX_MIN 0x00
+#define SEL_INDEX_MAX SEL_RECORDS_MAX
+
+// Record ID can not be 0x0 (IPMI/Section 31)
+#define SEL_RECID_MIN (SEL_INDEX_MIN+1)
+#define SEL_RECID_MAX (SEL_INDEX_MAX+1)
+
+// Special RecID value for first and last (IPMI/Section 31)
+#define SEL_RECID_FIRST 0x0000
+#define SEL_RECID_LAST 0xFFFF
+
+// SEL header struct to keep track of SEL Log entries
+typedef struct {
+ int magic; // Magic number to check validity
+ int version; // version number of this header
+ int begin; // index to the begining of the log
+ int end; // index to end of the log
+ time_stamp_t ts_add; // last addition time stamp
+ time_stamp_t ts_erase; // last erase time stamp
+} sel_hdr_t;
+
+// Keep track of last Reservation ID
+static int g_rsv_id = 0x01;
+
+// Cached version of SEL Header and data
+static sel_hdr_t g_sel_hdr;
+static sel_msg_t g_sel_data[SEL_ELEMS_MAX];
+
+// Local helper functions to interact with file system
+static int
+file_get_sel_hdr(void) {
+ FILE *fp;
+
+ fp = fopen(SEL_LOG_FILE, "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ if (fread(&g_sel_hdr, sizeof(sel_hdr_t), 1, fp) <= 0) {
+ syslog(LOG_ALERT, "file_get_sel_hdr: fread\n");
+ fclose (fp);
+ return -1;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+static int
+file_get_sel_data(void) {
+ FILE *fp;
+ int i, j;
+
+ fp = fopen(SEL_LOG_FILE, "r");
+ if (fp == NULL) {
+ syslog(LOG_ALERT, "file_get_sel_data: fopen\n");
+ return -1;
+ }
+
+ if (fseek(fp, SEL_DATA_OFFSET, SEEK_SET)) {
+ syslog(LOG_ALERT, "file_get_sel_data: fseek\n");
+ fclose(fp);
+ return -1;
+ }
+
+ unsigned char buf[SEL_ELEMS_MAX * 16];
+ if (fread(buf, 1, SEL_ELEMS_MAX * sizeof(sel_msg_t), fp) <= 0) {
+ syslog(LOG_ALERT, "file_get_sel_data: fread\n");
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+
+ for (i = 0; i < SEL_ELEMS_MAX; i++) {
+ for (j = 0; j < sizeof(sel_msg_t);j++) {
+ g_sel_data[i].msg[j] = buf[i*16 + j];
+ }
+ }
+
+ return 0;
+}
+
+static int
+file_store_sel_hdr(void) {
+ FILE *fp;
+
+ fp = fopen(SEL_LOG_FILE, "r+");
+ if (fp == NULL) {
+ syslog(LOG_ALERT, "file_store_sel_hdr: fopen\n");
+ return -1;
+ }
+
+ if (fwrite(&g_sel_hdr, sizeof(sel_hdr_t), 1, fp) <= 0) {
+ syslog(LOG_ALERT, "file_store_sel_hdr: fwrite\n");
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+static int
+file_store_sel_data(int recId, sel_msg_t *data) {
+ FILE *fp;
+ int index;
+
+ fp = fopen(SEL_LOG_FILE, "r+");
+ if (fp == NULL) {
+ syslog(LOG_ALERT, "file_store_sel_data: fopen\n");
+ return -1;
+ }
+
+ // Records are stored using zero-based index
+ index = (recId-1) * sizeof(sel_msg_t);
+
+ if (fseek(fp, SEL_DATA_OFFSET+index, SEEK_SET)) {
+ syslog(LOG_ALERT, "file_store_sel_data: fseek\n");
+ fclose(fp);
+ return -1;
+ }
+
+ if (fwrite(data->msg, sizeof(sel_msg_t), 1, fp) <= 0) {
+ syslog(LOG_ALERT, "file_store_sel_data: fwrite\n");
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+// Platform specific SEL API entry points
+// Retrieve time stamp for recent add operation
+void
+sel_ts_recent_add(time_stamp_t *ts) {
+ memcpy(ts->ts, g_sel_hdr.ts_add.ts, 0x04);
+}
+
+// Retrieve time stamp for recent erase operation
+void
+sel_ts_recent_erase(time_stamp_t *ts) {
+ memcpy(ts->ts, g_sel_hdr.ts_erase.ts, 0x04);
+}
+
+// Retrieve total number of entries in SEL log
+int
+sel_num_entries(void) {
+ if (g_sel_hdr.begin <= g_sel_hdr.end) {
+ return (g_sel_hdr.end - g_sel_hdr.begin);
+ } else {
+ return (g_sel_hdr.end + (SEL_INDEX_MAX - g_sel_hdr.begin + 1));
+ }
+}
+
+// Retrieve total free space available in SEL log
+int
+sel_free_space(void) {
+ int total_space;
+ int used_space;
+
+ total_space = SEL_RECORDS_MAX * sizeof(sel_msg_t);
+ used_space = sel_num_entries() * sizeof(sel_msg_t);
+
+ return (total_space - used_space);
+}
+
+// Reserve an ID that will be used in later operations
+// IPMI/Section 31.4
+int
+sel_rsv_id() {
+ // Increment the current reservation ID and return
+ if (g_rsv_id++ == SEL_RSVID_MAX) {
+ g_rsv_id = SEL_RSVID_MIN;
+ }
+
+ return g_rsv_id;
+}
+
+// Get the SEL entry for a given record ID
+// IPMI/Section 31.5
+int
+sel_get_entry(int read_rec_id, sel_msg_t *msg, int *next_rec_id) {
+
+ int index;
+
+ // Find the index in to array based on given index
+ if (read_rec_id == SEL_RECID_FIRST) {
+ index = g_sel_hdr.begin;
+ } else if (read_rec_id == SEL_RECID_LAST) {
+ if (g_sel_hdr.end) {
+ index = g_sel_hdr.end - 1;
+ } else {
+ index = SEL_INDEX_MAX;
+ }
+ } else {
+ index = read_rec_id - 1;
+ }
+
+ // If the log is empty return error
+ if (sel_num_entries() == 0) {
+ syslog(LOG_ALERT, "sel_get_entry: No entries\n");
+ return -1;
+ }
+
+ // Check for boundary conditions
+ if ((index < SEL_INDEX_MIN) || (index > SEL_INDEX_MAX)) {
+ syslog(LOG_ALERT, "sel_get_entry: Invalid Record ID %d\n", read_rec_id);
+ return -1;
+ }
+
+ // If begin < end, check to make sure the given id falls between
+ if (g_sel_hdr.begin < g_sel_hdr.end) {
+ if (index < g_sel_hdr.begin || index >= g_sel_hdr.end) {
+ syslog(LOG_ALERT, "sel_get_entry: Wrong Record ID %d\n", read_rec_id);
+ return -1;
+ }
+ }
+
+ // If end < begin, check to make sure the given id is valid
+ if (g_sel_hdr.begin > g_sel_hdr.end) {
+ if (index >= g_sel_hdr.end && index < g_sel_hdr.begin) {
+ syslog(LOG_ALERT, "sel_get_entry: Wrong Record ID2 %d\n", read_rec_id);
+ return -1;
+ }
+ }
+
+ memcpy(msg->msg, g_sel_data[index].msg, sizeof(sel_msg_t));
+
+ // Return the next record ID in the log
+ *next_rec_id = read_rec_id++;
+ if (*next_rec_id > SEL_INDEX_MAX) {
+ *next_rec_id = SEL_INDEX_MIN;
+ }
+
+ // If this is the last entry in the log, return 0xFFFF
+ if (*next_rec_id == g_sel_hdr.end) {
+ *next_rec_id = SEL_RECID_LAST;
+ }
+
+ return 0;
+}
+
+// Add a new entry in to SEL log
+// IPMI/Section 31.6
+int
+sel_add_entry(sel_msg_t *msg, int *rec_id) {
+ // If the SEL if full, roll over. To keep track of empty condition, use
+ // one empty location less than the max records.
+ if (sel_num_entries() == SEL_RECORDS_MAX) {
+ syslog(LOG_ALERT, "sel_add_entry: SEL rollover\n");
+ if (++g_sel_hdr.begin > SEL_INDEX_MAX) {
+ g_sel_hdr.begin = SEL_INDEX_MIN;
+ }
+ }
+
+ // Update message's time stamp starting at byte 4
+ time_stamp_fill(&msg->msg[3]);
+
+ // Add the enry at end
+ memcpy(g_sel_data[g_sel_hdr.end].msg, msg->msg, sizeof(sel_msg_t));
+
+ // Return the newly added record ID
+ *rec_id = g_sel_hdr.end+1;
+
+ if (file_store_sel_data(*rec_id, msg)) {
+ syslog(LOG_ALERT, "sel_add_entry: file_store_sel_data\n");
+ return -1;
+ }
+
+ // Increment the end pointer
+ if (++g_sel_hdr.end > SEL_INDEX_MAX) {
+ g_sel_hdr.end = SEL_INDEX_MIN;
+ }
+
+ // Update timestamp for add in header
+ time_stamp_fill(g_sel_hdr.ts_add.ts);
+
+ // Store the structure persistently
+ if (file_store_sel_hdr()) {
+ syslog(LOG_ALERT, "sel_add_entry: file_store_sel_hdr\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+// Erase the SEL completely
+// IPMI/Section 31.9
+// Note: To reduce wear/tear, instead of erasing, manipulating the metadata
+int
+sel_erase(int rsv_id) {
+ if (rsv_id != g_rsv_id) {
+ return -1;
+ }
+
+ // Erase SEL Logs
+ g_sel_hdr.begin = SEL_INDEX_MIN;
+ g_sel_hdr.end = SEL_INDEX_MIN;
+
+ // Update timestamp for erase in header
+ time_stamp_fill(g_sel_hdr.ts_erase.ts);
+
+ // Store the structure persistently
+ if (file_store_sel_hdr()) {
+ syslog(LOG_ALERT, "sel_erase: file_store_sel_hdr\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+// To get the erase status while erase happens
+// IPMI/Section 31.2
+// Note: Since we are not doing offline erasing, need not return in-progress state
+int
+sel_erase_status(int rsv_id, sel_erase_stat_t *status) {
+ if (rsv_id != g_rsv_id) {
+ return -1;
+ }
+
+ // Since we do not do any offline erasing, always return erase done
+ *status = SEL_ERASE_DONE;
+
+ return 0;
+}
+
+// Initialize SEL log file
+int
+sel_init(void) {
+ FILE *fp;
+ int i;
+
+ // Check if the file exists or not
+ if (access(SEL_LOG_FILE, F_OK) == 0) {
+ // Since file is present, fetch all the contents to cache
+ if (file_get_sel_hdr()) {
+ syslog(LOG_ALERT, "init_sel: file_get_sel_hdr\n");
+ return -1;
+ }
+
+ if (file_get_sel_data()) {
+ syslog(LOG_ALERT, "init_sel: file_get_sel_data\n");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ // File not present, so create the file
+ fp = fopen(SEL_LOG_FILE, "w+");
+ if (fp == NULL) {
+ syslog(LOG_ALERT, "init_sel: fopen\n");
+ return -1;
+ }
+
+ fclose (fp);
+
+ // Populate SEL Header in to the file
+ g_sel_hdr.magic = SEL_HDR_MAGIC;
+ g_sel_hdr.version = SEL_HDR_VERSION;
+ g_sel_hdr.begin = SEL_INDEX_MIN;
+ g_sel_hdr.end = SEL_INDEX_MIN;
+ memset(g_sel_hdr.ts_add.ts, 0x0, 4);
+ memset(g_sel_hdr.ts_erase.ts, 0x0, 4);
+
+ if (file_store_sel_hdr()) {
+ syslog(LOG_ALERT, "init_sel: file_store_sel_hdr\n");
+ return -1;
+ }
+
+ // Populate SEL Data in to the file
+ for (i = 1; i <= SEL_RECORDS_MAX; i++) {
+ sel_msg_t msg = {0};
+ if (file_store_sel_data(i, &msg)) {
+ syslog(LOG_ALERT, "init_sel: file_store_sel_data\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/common/recipes-core/ipmid/files/sel.h b/common/recipes-core/ipmid/files/sel.h
new file mode 100644
index 0000000..3bb9a2f
--- /dev/null
+++ b/common/recipes-core/ipmid/files/sel.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SEL_H__
+#define __SEL_H__
+
+#include "timestamp.h"
+
+enum {
+ IPMI_SEL_INIT_ERASE = 0xAA,
+ IPMI_SEL_ERASE_STAT = 0x00,
+};
+
+typedef enum {
+ SEL_ERASE_IN_PROG = 0x00,
+ SEL_ERASE_DONE = 0x01,
+} sel_erase_stat_t;
+
+typedef struct {
+ unsigned char msg[16];
+} sel_msg_t;
+
+void sel_ts_recent_add(time_stamp_t *ts);
+void sel_ts_recent_erase(time_stamp_t *ts);
+int sel_num_entries(void);
+int sel_free_space(void);
+int sel_rsv_id();
+int sel_get_entry(int read_rec_id, sel_msg_t *msg, int *next_rec_id);
+int sel_add_entry(sel_msg_t *msg, int *rec_id);
+int sel_erase(int rsv_id);
+int sel_erase_status(int rsv_id, sel_erase_stat_t *status);
+int sel_init(void);
+
+#endif /* __SEL_H__ */
diff --git a/common/recipes-core/ipmid/files/sensor.h b/common/recipes-core/ipmid/files/sensor.h
new file mode 100644
index 0000000..5d8c11a
--- /dev/null
+++ b/common/recipes-core/ipmid/files/sensor.h
@@ -0,0 +1,117 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SENSOR_H__
+#define __SENSOR_H__
+
+#include "timestamp.h"
+
+#define IANA_ID_SIZE 3
+#define SENSOR_STR_SIZE 16
+#define SENSOR_OEM_DATA_SIZE 56
+
+// Threshold Sensor Descriptor
+typedef struct {
+ unsigned char owner;
+ unsigned char lun;
+ unsigned char sensor_num;
+ unsigned char ent_id;
+ unsigned char ent_inst;
+ unsigned char sensor_init;
+ unsigned char sensor_caps;
+ unsigned char sensor_type;
+ unsigned char evt_read_type;
+ unsigned char lt_read_mask[2];
+ unsigned char ut_read_mask[2];
+ unsigned char set_thresh_mask[2];
+ unsigned char sensor_units1;
+ unsigned char sensor_units2;
+ unsigned char sensor_units3;
+ unsigned char linear;
+ unsigned char m_val;
+ unsigned char m_tolerance;
+ unsigned char b_val;
+ unsigned char b_accuracy;
+ unsigned char accuracy_dir;
+ unsigned char rb_exp;
+ unsigned char analog_flags;
+ unsigned char nominal;
+ unsigned char normal_max;
+ unsigned char normal_min;
+ unsigned char max_reading;
+ unsigned char min_reading;
+ unsigned char unr_thresh;
+ unsigned char uc_thresh;
+ unsigned char unc_thresh;
+ unsigned char lnr_thresh;
+ unsigned char lc_thresh;
+ unsigned char lnc_thresh;
+ unsigned char pos_hyst;
+ unsigned char neg_hyst;
+ unsigned char oem;
+ unsigned char str_type_len;
+ char str[SENSOR_STR_SIZE];
+} sensor_thresh_t;
+
+// Discrete Sensor Descriptor
+typedef struct {
+ unsigned char owner;
+ unsigned char lun;
+ unsigned char sensor_num;
+ unsigned char ent_id;
+ unsigned char ent_inst;
+ unsigned char sensor_init;
+ unsigned char sensor_caps;
+ unsigned char sensor_type;
+ unsigned char evt_read_type;
+ unsigned char assert_evt_mask[2];
+ unsigned char deassert_evt_mask[2];
+ unsigned char read_evt_mask[2];
+ unsigned char oem;
+ unsigned char str_type_len;
+ char str[SENSOR_STR_SIZE];
+} sensor_disc_t;
+
+// Mgmt. Controller Sensor Descriptor
+typedef struct {
+ unsigned char slave_addr;
+ unsigned char chan_no;
+ unsigned char pwr_state_init;
+ unsigned char dev_caps;
+ unsigned char ent_id;
+ unsigned char ent_inst;
+ unsigned char oem;
+ unsigned char str_type_len;
+ char str[SENSOR_STR_SIZE];
+} sensor_mgmt_t;
+
+// OEM type Sensor Descriptor
+typedef struct {
+ unsigned char mfr_id[IANA_ID_SIZE];
+ unsigned char oem_data[SENSOR_OEM_DATA_SIZE];
+} sensor_oem_t;
+
+void plat_sensor_mgmt_info(int *num, sensor_mgmt_t **p_sensor);
+void plat_sensor_disc_info(int *num, sensor_disc_t **p_sensor);
+void plat_sensor_thresh_info(int *num, sensor_thresh_t **p_sensor);
+void plat_sensor_oem_info(int *num, sensor_oem_t **p_sensor);
+int plat_sensor_init(void);
+
+#endif /* __SENSOR_H__ */
diff --git a/common/recipes-core/ipmid/files/timestamp.c b/common/recipes-core/ipmid/files/timestamp.c
new file mode 100644
index 0000000..11ac03e
--- /dev/null
+++ b/common/recipes-core/ipmid/files/timestamp.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This file is a helper file to fill timestamps from platform
+ * used by SEL Logs, SDR records etc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+// Local helper function to fill time stamp
+void
+time_stamp_fill(unsigned char *ts) {
+ unsigned int time;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ time = tv.tv_sec;
+ ts[0] = time & 0xFF;
+ ts[1] = (time >> 8) & 0xFF;
+ ts[2] = (time >> 16) & 0xFF;
+ ts[3] = (time >> 24) & 0xFF;
+
+ return;
+}
diff --git a/common/recipes-core/ipmid/files/timestamp.h b/common/recipes-core/ipmid/files/timestamp.h
new file mode 100644
index 0000000..430dd23
--- /dev/null
+++ b/common/recipes-core/ipmid/files/timestamp.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __TIMESTAMP_H__
+#define __TIMESTAMP_H__
+
+typedef struct {
+ unsigned char ts[4];
+} time_stamp_t;
+
+void time_stamp_fill(unsigned char *ts);
+
+#endif /* __TIMESTAMP_H__ */
diff --git a/common/recipes-core/ipmid/ipmid_0.2.bb b/common/recipes-core/ipmid/ipmid_0.2.bb
new file mode 100644
index 0000000..14c8c7f
--- /dev/null
+++ b/common/recipes-core/ipmid/ipmid_0.2.bb
@@ -0,0 +1,42 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "IPMI Daemon"
+DESCRIPTION = "Daemon to handle IPMI Messages."
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://ipmid.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec"
+
+
+SRC_URI = "file://Makefile \
+ file://ipmid.c \
+ file://timestamp.c \
+ file://timestamp.h \
+ file://sel.c \
+ file://sel.h \
+ file://sdr.c \
+ file://sdr.h \
+ file://sensor.h \
+ file://fruid.h \
+ "
+
+DEPENDS += " libpal "
+
+binfiles = "ipmid"
+
+pkgdir = "ipmid"
diff --git a/common/recipes-core/power-util/files/Makefile b/common/recipes-core/power-util/files/Makefile
new file mode 100644
index 0000000..97ee9d5
--- /dev/null
+++ b/common/recipes-core/power-util/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: power-util
+
+
+power-util: power-util.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o power-util
diff --git a/common/recipes-core/power-util/files/power-util.c b/common/recipes-core/power-util/files/power-util.c
new file mode 100644
index 0000000..0fda9d6
--- /dev/null
+++ b/common/recipes-core/power-util/files/power-util.c
@@ -0,0 +1,295 @@
+/*
+ * power-util
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <openbmc/pal.h>
+
+#define POWER_ON_STR "on"
+#define POWER_OFF_STR "off"
+
+const char *pwr_option_list = "status, graceful-shutdown, off, on, cycle, 12V-off,"
+ "12V-on, 12V-cycle";
+
+enum {
+ PWR_STATUS = 1,
+ PWR_GRACEFUL_SHUTDOWN,
+ PWR_OFF,
+ PWR_ON,
+ PWR_CYCLE,
+ PWR_12V_OFF,
+ PWR_12V_ON,
+ PWR_12V_CYCLE,
+ PWR_SLED_CYCLE
+};
+
+static int
+set_last_pwr_state(uint8_t fru, char * state) {
+
+ int ret;
+ char key[MAX_KEY_LEN] = {0};
+
+ sprintf(key, "pwr_server%d_last_state", (int) fru);
+
+ ret = pal_set_key_value(key, state);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "set_last_pwr_state: pal_set_key_value failed for "
+ "fru %u", fru);
+ }
+ return ret;
+}
+
+static void
+print_usage() {
+ printf("Usage: power-util [ %s ] [ %s ]\nUsage: power-util sled-cycle\n",
+ pal_server_list, pwr_option_list);
+}
+
+static int
+get_power_opt(char *option, uint8_t *opt) {
+
+ if (!strcmp(option, "status")) {
+ *opt = PWR_STATUS;
+ } else if (!strcmp(option, "graceful-shutdown")) {
+ *opt = PWR_GRACEFUL_SHUTDOWN;
+ } else if (!strcmp(option, "off")) {
+ *opt = PWR_OFF;
+ } else if (!strcmp(option, "on")) {
+ *opt = PWR_ON;
+ } else if (!strcmp(option, "cycle")) {
+ *opt = PWR_CYCLE;
+ } else if (!strcmp(option, "12V-off")) {
+ *opt = PWR_12V_OFF;
+ } else if (!strcmp(option, "12V-on")) {
+ *opt = PWR_12V_ON;
+ } else if (!strcmp(option, "12V-cycle")) {
+ *opt = PWR_12V_CYCLE;
+ } else if (!strcmp(option, "sled-cycle")) {
+ *opt = PWR_SLED_CYCLE;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+power_util(uint8_t fru, uint8_t opt) {
+
+ int ret;
+ uint8_t status;
+
+ switch(opt) {
+ case PWR_STATUS:
+ ret = pal_get_server_power(fru, &status);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_get_server_power failed for fru %u\n", fru);
+ return ret;
+ }
+ printf("Power status for fru %u : %s\n", fru, status?"ON":"OFF");
+ break;
+
+ case PWR_GRACEFUL_SHUTDOWN:
+
+ printf("Shutting down fru %u gracefully...\n", fru);
+
+ ret = pal_set_server_power(fru, SERVER_GRACEFUL_SHUTDOWN);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_server_power failed for"
+ " fru %u", fru);
+ return ret;
+ } else if (ret == 1) {
+ printf("fru %u is already powered OFF...\n", fru);
+ return 0;
+ }
+
+ ret = set_last_pwr_state(fru, POWER_OFF_STR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_set_led(fru, LED_STATE_OFF);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_led failed for fru %u", fru);
+ return ret;
+ }
+ break;
+
+ case PWR_OFF:
+
+ printf("Powering fru %u to OFF state...\n", fru);
+
+ ret = pal_set_server_power(fru, SERVER_POWER_OFF);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_server_power failed for"
+ " fru %u", fru);
+ return ret;
+ } else if (ret == 1) {
+ printf("fru %u is already powered OFF...\n", fru);
+ return 0;
+ }
+
+ ret = set_last_pwr_state(fru, POWER_OFF_STR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_set_led(fru, LED_STATE_OFF);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_led failed for fru %u", fru);
+ return ret;
+ }
+ break;
+
+ case PWR_ON:
+
+ printf("Powering fru %u to ON state...\n", fru);
+
+ ret = pal_set_server_power(fru, SERVER_POWER_ON);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_server_power failed for"
+ " fru %u", fru);
+ return ret;
+ } else if (ret == 1) {
+ printf("fru %u is already powered ON...\n", fru);
+ return 0;
+ }
+
+ ret = set_last_pwr_state(fru, POWER_ON_STR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_set_led(fru, LED_STATE_ON);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_led failed for fru %u", fru);
+ return ret;
+ }
+ break;
+
+ case PWR_CYCLE:
+
+ printf("Power cycling fru %u...\n", fru);
+
+ ret = pal_set_server_power(fru, SERVER_POWER_CYCLE);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_server_power failed for"
+ " fru %u", fru);
+ return ret;
+ }
+
+ ret = set_last_pwr_state(fru, POWER_ON_STR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = pal_set_led(fru, LED_STATE_ON);
+ if (ret < 0) {
+ syslog(LOG_ALERT, "power_util: pal_set_led failed for fru %u", fru);
+ return ret;
+ }
+ break;
+
+ case PWR_12V_OFF:
+ ret = 0; // TODO: Need to add the API to support this power state setting
+ break;
+
+ case PWR_12V_ON:
+ ret = 0; // TODO: Need to add the API to support this power state setting
+ break;
+
+ case PWR_12V_CYCLE:
+ ret = 0; // TODO: Need to add the API to support this power state setting
+ break;
+
+ case PWR_SLED_CYCLE:
+ pal_sled_cycle();
+ break;
+
+ default:
+ syslog(LOG_ALERT, "power_util: wrong option");
+
+ }
+
+ return ret;
+}
+
+int
+main(int argc, char **argv) {
+
+ int ret;
+
+ uint8_t fru, status, opt;
+ char *option;
+
+ /* Check for sled-cycle */
+ if (argc < 2 || argc > 3) {
+ print_usage();
+ exit (-1);
+ }
+
+ option = argc == 2 ? argv[1] : argv [2];
+
+ ret = get_power_opt(option, &opt);
+ /* If argc is 2, the option is sled-cycle */
+ if ((ret < 0) || (argc == 2 && opt != PWR_SLED_CYCLE)) {
+ printf("Wrong option: %s\n", option);
+ print_usage();
+ exit(-1);
+ }
+
+ if (argc > 2) {
+ ret = pal_get_fru_id(argv[1], &fru);
+ if (ret < 0) {
+ printf("Wrong fru: %s\n", argv[1]);
+ print_usage();
+ exit(-1);
+ }
+ } else {
+ fru = -1;
+ }
+
+ if (argc > 2) {
+ ret = pal_is_server_prsnt(fru, &status);
+ if (ret < 0) {
+ printf("pal_is_server_prsnt failed for fru: %d\n", fru);
+ print_usage();
+ exit(-1);
+ }
+ if (status == 0) {
+ printf("%s is empty!\n", argv[1]);
+ print_usage();
+ exit(-1);
+ }
+ }
+
+ ret = power_util(fru, opt);
+ if (ret < 0) {
+ print_usage();
+ return ret;
+ }
+}
diff --git a/common/recipes-core/power-util/power-util_0.1.bb b/common/recipes-core/power-util/power-util_0.1.bb
new file mode 100644
index 0000000..69ef2ad
--- /dev/null
+++ b/common/recipes-core/power-util/power-util_0.1.bb
@@ -0,0 +1,36 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "Power Utility"
+DESCRIPTION = "Utility for Power Policy and Management"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://power-util.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238"
+
+SRC_URI = "file://Makefile \
+ file://power-util.c \
+ "
+S = "${WORKDIR}"
+
+LDFLAGS =+ " -lpal "
+
+DEPENDS =+ " libpal "
+
+binfiles = "power-util"
+
+pkgdir = "power-util"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ install -m 755 power-util ${dst}/power-util
+ ln -snf ../fbpackages/${pkgdir}/power-util ${bin}/power-util
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/power-util ${prefix}/local/bin"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/sensor-mon/files/Makefile b/common/recipes-core/sensor-mon/files/Makefile
new file mode 100644
index 0000000..68a9fe7
--- /dev/null
+++ b/common/recipes-core/sensor-mon/files/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+all: sensord
+
+sensord: sensord.c
+ $(CC) $(CFLAGS) -D _XOPEN_SOURCE -pthread -lm -std=c99 -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o sensord
diff --git a/common/recipes-core/sensor-mon/files/sensord.c b/common/recipes-core/sensor-mon/files/sensord.c
new file mode 100644
index 0000000..1852af3
--- /dev/null
+++ b/common/recipes-core/sensor-mon/files/sensord.c
@@ -0,0 +1,1031 @@
+/*
+ * sensord
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/file.h>
+#include <facebook/bic.h>
+#include <openbmc/ipmi.h>
+#include <openbmc/sdr.h>
+#ifdef CONFIG_YOSEMITE
+#include <facebook/yosemite_sensor.h>
+#endif /* CONFIG_YOSEMITE */
+
+#define MAX_SENSOR_NUM 0xFF
+#define NORMAL_STATE 0x00
+
+#define SETBIT(x, y) (x | (1 << y))
+#define GETBIT(x, y) ((x & (1 << y)) > y)
+#define CLEARBIT(x, y) (x & (~(1 << y)))
+#define GETMASK(y) (1 << y)
+
+
+
+/* Enum for type of Upper and Lower threshold values */
+enum {
+ UCR_THRESH = 0x01,
+ UNC_THRESH,
+ UNR_THRESH,
+ LCR_THRESH,
+ LNC_THRESH,
+ LNR_THRESH,
+ POS_HYST,
+ NEG_HYST,
+};
+
+/* To hold the sensor info and calculated threshold values from the SDR */
+typedef struct {
+ uint8_t flag;
+ float ucr_thresh;
+ float unc_thresh;
+ float unr_thresh;
+ float lcr_thresh;
+ float lnc_thresh;
+ float lnr_thresh;
+ float pos_hyst;
+ float neg_hyst;
+ int curr_state;
+ char name[23];
+ char units[64];
+
+} thresh_sensor_t;
+
+/* Function pointer to read sensor current value */
+static int (*read_snr_val)(uint8_t, uint8_t, void *);
+
+#ifdef CONFIG_YOSEMITE
+
+// TODO: Change to 6 after adding SPB and NIC
+#define MAX_NUM_FRUS 4
+#define YOSEMITE_SDR_PATH "/tmp/sdr_%s.bin"
+
+static thresh_sensor_t snr_slot1[MAX_SENSOR_NUM] = {0};
+static thresh_sensor_t snr_slot2[MAX_SENSOR_NUM] = {0};
+static thresh_sensor_t snr_slot3[MAX_SENSOR_NUM] = {0};
+static thresh_sensor_t snr_slot4[MAX_SENSOR_NUM] = {0};
+static thresh_sensor_t snr_spb[MAX_SENSOR_NUM] = {0};
+static thresh_sensor_t snr_nic[MAX_SENSOR_NUM] = {0};
+
+static sensor_info_t sinfo_slot1[MAX_SENSOR_NUM] = {0};
+static sensor_info_t sinfo_slot2[MAX_SENSOR_NUM] = {0};
+static sensor_info_t sinfo_slot3[MAX_SENSOR_NUM] = {0};
+static sensor_info_t sinfo_slot4[MAX_SENSOR_NUM] = {0};
+static sensor_info_t sinfo_spb[MAX_SENSOR_NUM] = {0};
+static sensor_info_t sinfo_nic[MAX_SENSOR_NUM] = {0};
+#endif /* CONFIG_YOSEMITE */
+
+
+/*
+ * Returns the pointer to the struct holding all sensor info and
+ * calculated threshold values for the fru#
+ */
+static thresh_sensor_t *
+get_struct_thresh_sensor(uint8_t fru) {
+
+ thresh_sensor_t *snr;
+
+#ifdef CONFIG_YOSEMITE
+ switch (fru) {
+ case FRU_SLOT1:
+ snr = snr_slot1;
+ break;
+ case FRU_SLOT2:
+ snr = snr_slot2;
+ break;
+ case FRU_SLOT3:
+ snr = snr_slot3;
+ break;
+ case FRU_SLOT4:
+ snr = snr_slot4;
+ break;
+ case FRU_SPB:
+ snr = snr_spb;
+ break;
+ case FRU_NIC:
+ snr = snr_nic;
+ break;
+ default:
+ syslog(LOG_ALERT, "get_struct_thresh_sensor: Wrong FRU ID %d\n", fru);
+ return NULL;
+ }
+#endif /* CONFIG_YOSEMITE */
+
+ return snr;
+}
+
+
+/* Returns the all the SDRs for the particular fru# */
+static sensor_info_t *
+get_struct_sensor_info(uint8_t fru) {
+
+ sensor_info_t *sinfo;
+
+#ifdef CONFIG_YOSEMITE
+ switch (fru) {
+ case FRU_SLOT1:
+ sinfo = sinfo_slot1;
+ break;
+ case FRU_SLOT2:
+ sinfo = sinfo_slot2;
+ break;
+ case FRU_SLOT3:
+ sinfo = sinfo_slot3;
+ break;
+ case FRU_SLOT4:
+ sinfo = sinfo_slot4;
+ break;
+ case FRU_SPB:
+ sinfo = sinfo_spb;
+ break;
+ case FRU_NIC:
+ sinfo = sinfo_nic;
+ break;
+ default:
+ syslog(LOG_ALERT, "get_struct_sensor_info: Wrong FRU ID %d\n", fru);
+ return NULL;
+ }
+#endif /* CONFIG_YOSEMITE */
+
+ return sinfo;
+}
+
+
+/* Returns the SDR for a particular sensor of particular fru# */
+static sdr_full_t *
+get_struct_sdr(uint8_t fru, uint8_t snr_num) {
+
+ sdr_full_t *sdr;
+ sensor_info_t *sinfo;
+ sinfo = get_struct_sensor_info(fru);
+ if (sinfo == NULL) {
+ syslog(LOG_ALERT, "get_struct_sdr: get_struct_sensor_info failed\n");
+ return NULL;
+ }
+ sdr = &sinfo[snr_num].sdr;
+ return sdr;
+}
+
+/* Get the threshold values from the SDRs */
+static int
+get_sdr_thresh_val(uint8_t fru, uint8_t snr_num, uint8_t thresh, void *value) {
+
+ int ret;
+ uint8_t x;
+ uint8_t m_lsb, m_msb, m;
+ uint8_t b_lsb, b_msb, b;
+ int8_t b_exp, r_exp;
+ uint8_t thresh_val;
+ sdr_full_t *sdr;
+
+ sdr = get_struct_sdr(fru, snr_num);
+ if (sdr == NULL) {
+ syslog(LOG_ALERT, "get_sdr_thresh_val: get_struct_sdr failed\n");
+ return -1;
+ }
+
+ switch (thresh) {
+ case UCR_THRESH:
+ thresh_val = sdr->uc_thresh;
+ break;
+ case UNC_THRESH:
+ thresh_val = sdr->unc_thresh;
+ break;
+ case UNR_THRESH:
+ thresh_val = sdr->unr_thresh;
+ break;
+ case LCR_THRESH:
+ thresh_val = sdr->lc_thresh;
+ break;
+ case LNC_THRESH:
+ thresh_val = sdr->lnc_thresh;
+ break;
+ case LNR_THRESH:
+ thresh_val = sdr->lnr_thresh;
+ break;
+ case POS_HYST:
+ thresh_val = sdr->pos_hyst;
+ break;
+ case NEG_HYST:
+ thresh_val = sdr->neg_hyst;
+ break;
+ default:
+ syslog(LOG_ERR, "get_sdr_thresh_val: reading unknown threshold val");
+ return -1;
+ }
+
+ // y = (mx + b * 10^b_exp) * 10^r_exp
+ x = thresh_val;
+
+ m_lsb = sdr->m_val;
+ m_msb = sdr->m_tolerance >> 6;
+ m = (m_msb << 8) | m_lsb;
+
+ b_lsb = sdr->b_val;
+ b_msb = sdr->b_accuracy >> 6;
+ b = (b_msb << 8) | b_lsb;
+
+ // exponents are 2's complement 4-bit number
+ b_exp = sdr->rb_exp & 0xF;
+ if (b_exp > 7) {
+ b_exp = (~b_exp + 1) & 0xF;
+ b_exp = -b_exp;
+ }
+ r_exp = (sdr->rb_exp >> 4) & 0xF;
+ if (r_exp > 7) {
+ r_exp = (~r_exp + 1) & 0xF;
+ r_exp = -r_exp;
+ }
+
+ * (float *) value = ((m * x) + (b * pow(10, b_exp))) * (pow(10, r_exp));
+
+ return 0;
+}
+
+/*
+ * Populate all fields of thresh_sensor_t struct for a particular sensor.
+ * Incase the threshold value is 0 mask the check for that threshvold
+ * value in flag field.
+ */
+int
+init_snr_thresh(uint8_t fru, uint8_t snr_num, uint8_t flag) {
+
+ int value;
+ float fvalue;
+ uint8_t op, modifier;
+ thresh_sensor_t *snr;
+
+ sdr_full_t *sdr;
+
+ sdr = get_struct_sdr(fru, snr_num);
+ if (sdr == NULL) {
+ syslog(LOG_ALERT, "init_snr_name: get_struct_sdr failed\n");
+ return -1;
+ }
+
+ snr = get_struct_thresh_sensor(fru);
+ if (snr == NULL) {
+ syslog(LOG_ALERT, "init_snr_thresh: get_struct_thresh_sensor failed");
+ return -1;
+ }
+
+ snr[snr_num].flag = flag;
+ snr[snr_num].curr_state = NORMAL_STATE;
+
+ if (sdr_get_sensor_name(sdr, snr[snr_num].name)) {
+ syslog(LOG_ALERT, "sdr_get_sensor_name: FRU %d: num: 0x%X: reading name"
+ " from SDR failed.", fru, snr_num);
+ return -1;
+ }
+
+ // TODO: Add support for modifier (Mostly modifier is zero)
+ if (sdr_get_sensor_units(sdr, &op, &modifier, snr[snr_num].units)) {
+ syslog(LOG_ALERT, "sdr_get_sensor_units: FRU %d: num 0x%X: reading units"
+ " from SDR failed.", fru, snr_num);
+ return -1;
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, UCR_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UCR_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].ucr_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, UCR_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, UCR_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, UNC_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UNC_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].unc_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, UNC_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, UNC_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, UNR_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UNR_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].unr_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, UNR_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, UNR_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, LCR_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LCR_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].lcr_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, LCR_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, LCR_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, LNC_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LNC_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].lnc_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, LNC_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, LNC_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, LNR_THRESH, &fvalue)) {
+ syslog(LOG_ERR,
+ "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LNR_THRESH",
+ fru, snr_num, snr[snr_num].name);
+ } else {
+ snr[snr_num].lnr_thresh = fvalue;
+ if (!(fvalue)) {
+ snr[snr_num].flag = CLEARBIT(snr[snr_num].flag, LNR_THRESH);
+ syslog(LOG_ALERT,
+ "FRU: %d, num: 0x%X, %-16s, LNR_THRESH check disabled val->%.2f",
+ fru, snr_num, snr[snr_num].name, fvalue);
+ }
+ }
+
+ if (get_sdr_thresh_val(fru, snr_num, POS_HYST, &fvalue)) {
+ syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, POS_HYST",
+ fru, snr_num, snr[snr_num].name);
+ } else
+ snr[snr_num].pos_hyst = fvalue;
+
+ if (get_sdr_thresh_val(fru, snr_num, NEG_HYST, &fvalue)) {
+ syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, NEG_HYST",
+ fru, snr_num, snr[snr_num].name);
+ } else
+ snr[snr_num].neg_hyst = fvalue;
+
+ return 0;
+}
+
+#ifdef CONFIG_YOSEMITE
+/* Initialize all thresh_sensor_t structs for all the Yosemite sensors */
+static void
+init_yosemite_snr_thresh(uint8_t fru) {
+
+ int i;
+
+ switch (fru) {
+ case FRU_SLOT1:
+ case FRU_SLOT2:
+ case FRU_SLOT3:
+ case FRU_SLOT4:
+
+ for (i < 0; i < bic_sensor_cnt; i++) {
+ init_snr_thresh(fru, bic_sensor_list[i], GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+ }
+ /*
+ init_snr_thresh(fru, BIC_SENSOR_MB_OUTLET_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCCIN_VR_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_GBE_VR_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_1V05PCH_VR_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_MB_INLET_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_PCH_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_THERM_MARGIN, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VDDR_VR_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_GBE_VR_CURR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_1V05_PCH_VR_CURR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCCIN_VR_POUT, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCCIN_VR_CURR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCCIN_VR_VOL,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_INA230_POWER, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_PACKAGE_PWR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_TJMAX, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VDDR_VR_POUT, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VDDR_VR_CURR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VDDR_VR_VOL,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_SCSUS_VR_CURR, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_SCSUS_VR_VOL,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_SCSUS_VR_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_SCSUS_VR_POUT, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_GBE_VR_POUT, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_VCC_GBE_VR_VOL,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_1V05_PCH_VR_VOL,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_DIMMA0_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_DIMMA1_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_DIMMB0_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_SOC_DIMMB1_TEMP, GETMASK(UCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_P3V3_MB,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_P12V_MB,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_P1V05_PCH,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_P3V3_STBY_MB,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_P5V_STBY_MB,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_PV_BAT,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_PVDDR,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+
+ init_snr_thresh(fru, BIC_SENSOR_PVCC_GBE,
+ GETMASK(UCR_THRESH) | GETMASK(LCR_THRESH));
+ // TODO: Add Support for Discrete sensors
+ // init_snr_thresh(fru, BIC_SENSOR_POST_ERR, //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_SYSTEM_STATUS, //Discrete
+ // init_snr_thresh(fru, BIC_SENSOR_SPS_FW_HLTH); //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_POWER_THRESH_EVENT, //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_MACHINE_CHK_ERR, //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_PCIE_ERR); //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_OTHER_IIO_ERR); //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_PROC_HOT_EXT); //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_POWER_ERR); //Event-only
+ // init_snr_thresh(fru, , ); //Event-only
+ // init_snr_thresh(fru, BIC_SENSOR_PROC_FAIL); //Discrete
+ // init_snr_thresh(fru, BIC_SENSOR_SYS_BOOT_STAT ); //Discrete
+ // init_snr_thresh(fru, BIC_SENSOR_VR_HOT); //Discrete
+ // init_snr_thresh(fru, BIC_SENSOR_CPU_DIMM_HOT ); //Discrete
+ // init_snr_thresh(fru, BIC_SENSOR_CAT_ERR, //Event-only
+
+ */
+
+ break;
+
+ case FRU_SPB:
+ // TODO: Add support for threshold calculation for SP sensors
+ /*
+ init_snr_thresh(fru, SP_SENSOR_INLET_TEMP, "SP_SENSOR_INLET_TEMP");
+ init_snr_thresh(fru, SP_SENSOR_OUTLET_TEMP, "SP_SENSOR_OUTLET_TEMP");
+ init_snr_thresh(fru, SP_SENSOR_MEZZ_TEMP, "SP_SENSOR_MEZZ_TEMP");
+ init_snr_thresh(fru, SP_SENSOR_FAN0_TACH, "SP_SENSOR_FAN0_TACH");
+ init_snr_thresh(fru, SP_SENSOR_FAN1_TACH, "SP_SENSOR_FAN1_TACH");
+ init_snr_thresh(fru, SP_SENSOR_AIR_FLOW, "SP_SENSOR_AIR_FLOW");
+ init_snr_thresh(fru, SP_SENSOR_P5V, "SP_SENSOR_P5V");
+ init_snr_thresh(fru, SP_SENSOR_P12V, "SP_SENSOR_P12V");
+ init_snr_thresh(fru, SP_SENSOR_P3V3_STBY, "SP_SENSOR_P3V3_STBY");
+ init_snr_thresh(fru, SP_SENSOR_P12V_SLOT0, "SP_SENSOR_P12V_SLOT0");
+ init_snr_thresh(fru, SP_SENSOR_P12V_SLOT1, "SP_SENSOR_P12V_SLOT1");
+ init_snr_thresh(fru, SP_SENSOR_P12V_SLOT2, "SP_SENSOR_P12V_SLOT2");
+ init_snr_thresh(fru, SP_SENSOR_P12V_SLOT3, "SP_SENSOR_P12V_SLOT3");
+ init_snr_thresh(fru, SP_SENSOR_P3V3, "SP_SENSOR_P3V3");
+ init_snr_thresh(fru, SP_SENSOR_HSC_IN_VOLT, "SP_SENSOR_HSC_IN_VOLT");
+ init_snr_thresh(fru, SP_SENSOR_HSC_OUT_CURR, "SP_SENSOR_HSC_OUT_CURR");
+ init_snr_thresh(fru, SP_SENSOR_HSC_TEMP, "SP_SENSOR_HSC_TEMP");
+ init_snr_thresh(fru, SP_SENSOR_HSC_IN_POWER, "SP_SENSOR_HSC_IN_POWER");
+ */
+ break;
+
+ case FRU_NIC:
+ // TODO: Add support for NIC sensor threshold, if any.
+ break;
+
+ default:
+ syslog(LOG_ALERT, "init_yosemite_snr_thresh: wrong FRU ID");
+ exit(-1);
+ }
+}
+#endif /* CONFIG_YOSEMITE */
+
+/* Wrapper function to initialize all the platform sensors */
+static void
+init_all_snr_thresh() {
+ int fru;
+
+ char path[64] = {0};
+ sensor_info_t *sinfo;
+
+
+#ifdef CONFIG_YOSEMITE
+ for (fru = FRU_SLOT1; fru < (FRU_SLOT1 + MAX_NUM_FRUS); fru++) {
+
+ if (get_fru_sdr_path(fru, path) < 0) {
+ syslog(LOG_ALERT, "yosemite_sdr_init: get_fru_sdr_path failed\n");
+ continue;
+ }
+#endif /* CONFIG_YOSEMITE */
+
+ sinfo = get_struct_sensor_info(fru);
+
+ if (sdr_init(path, sinfo) < 0)
+ syslog(LOG_ERR, "init_all_snr_thresh: sdr_init failed for FRU %d", fru);
+ }
+
+#ifdef CONFIG_YOSEMITE
+ for (fru = FRU_SLOT1; fru < (FRU_SLOT1 + MAX_NUM_FRUS); fru++) {
+ init_yosemite_snr_thresh(fru);
+ }
+#endif /* CONFIG_YOSEMITE */
+}
+
+
+
+
+static float
+get_snr_thresh_val(uint8_t fru, uint8_t snr_num, uint8_t thresh) {
+
+ float val;
+ thresh_sensor_t *snr;
+
+ snr = get_struct_thresh_sensor(fru);
+
+ switch (thresh) {
+ case UCR_THRESH:
+ val = snr[snr_num].ucr_thresh;
+ break;
+ case UNC_THRESH:
+ val = snr[snr_num].unc_thresh;
+ break;
+ case UNR_THRESH:
+ val = snr[snr_num].unr_thresh;
+ break;
+ case LCR_THRESH:
+ val = snr[snr_num].lcr_thresh;
+ break;
+ case LNC_THRESH:
+ val = snr[snr_num].lnc_thresh;
+ break;
+ case LNR_THRESH:
+ val = snr[snr_num].lnr_thresh;
+ break;
+ default:
+ syslog(LOG_ALERT, "get_snr_thresh_val: wrong thresh enum value");
+ exit(-1);
+ }
+
+ return val;
+}
+
+/*
+ * Check the curr sensor values against the threshold and
+ * if the curr val has deasserted, log it.
+ */
+static void
+check_thresh_deassert(uint8_t fru, uint8_t snr_num, uint8_t thresh,
+ float curr_val) {
+ uint8_t curr_state = 0;
+ float thresh_val;
+ char thresh_name[100];
+ thresh_sensor_t *snr;
+
+ snr = get_struct_thresh_sensor(fru);
+
+ if (!GETBIT(snr[snr_num].flag, thresh) ||
+ !GETBIT(snr[snr_num].curr_state, thresh))
+ return;
+
+ thresh_val = get_snr_thresh_val(fru, snr_num, thresh);
+
+ switch (thresh) {
+ case UNC_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, UNR_THRESH) |
+ SETBIT(curr_state, UCR_THRESH) |
+ SETBIT(curr_state, UNC_THRESH));
+ sprintf(thresh_name, "Upper Non Critical");
+ }
+ break;
+
+ case UCR_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, UCR_THRESH) |
+ SETBIT(curr_state, UNR_THRESH));
+ sprintf(thresh_name, "Upper Critical");
+ }
+ break;
+
+ case UNR_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, UNR_THRESH));
+ sprintf(thresh_name, "Upper Non Recoverable");
+ }
+ break;
+
+ case LNC_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, LNR_THRESH) |
+ SETBIT(curr_state, LCR_THRESH) |
+ SETBIT(curr_state, LNC_THRESH));
+ sprintf(thresh_name, "Lower Non Critical");
+ }
+ break;
+
+ case LCR_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, LCR_THRESH) |
+ SETBIT(curr_state, LNR_THRESH));
+ sprintf(thresh_name, "Lower Critical");
+ }
+ break;
+
+ case LNR_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = ~(SETBIT(curr_state, LNR_THRESH));
+ sprintf(thresh_name, "Lower Non Recoverable");
+ }
+ break;
+
+ default:
+ syslog(LOG_ALERT, "get_snr_thresh_val: wrong thresh enum value");
+ exit(-1);
+ }
+
+ if (curr_state) {
+ snr[snr_num].curr_state &= curr_state;
+ syslog(LOG_CRIT, "DEASSERT: %s threshold raised - FRU: %d, num: 0x%X,"
+ " snr: %-16s,",thresh_name, fru, snr_num, snr[snr_num].name);
+ syslog(LOG_CRIT, "curr_val: %.2f %s, thresh_val: %.2f %s cf: %u",
+ curr_val, snr[snr_num].units, thresh_val, snr[snr_num].units, snr[snr_num].curr_state);
+ }
+}
+
+
+/*
+ * Check the curr sensor values against the threshold and
+ * if the curr val has asserted, log it.
+ */
+static void
+check_thresh_assert(uint8_t fru, uint8_t snr_num, uint8_t thresh,
+ float curr_val) {
+ uint8_t curr_state = 0;
+ float thresh_val;
+ char thresh_name[100];
+ thresh_sensor_t *snr;
+
+ snr = get_struct_thresh_sensor(fru);
+
+ if (!GETBIT(snr[snr_num].flag, thresh) ||
+ GETBIT(snr[snr_num].curr_state, thresh))
+ return;
+
+ thresh_val = get_snr_thresh_val(fru, snr_num, thresh);
+
+ switch (thresh) {
+ case UNR_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = (SETBIT(curr_state, UNR_THRESH) |
+ SETBIT(curr_state, UCR_THRESH) |
+ SETBIT(curr_state, UNC_THRESH));
+ sprintf(thresh_name, "Upper Non Recoverable");
+ }
+ break;
+
+ case UCR_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = (SETBIT(curr_state, UCR_THRESH) |
+ SETBIT(curr_state, UNC_THRESH));
+ sprintf(thresh_name, "Upper Critical");
+ }
+ break;
+
+ case UNC_THRESH:
+ if (curr_val >= thresh_val) {
+ curr_state = (SETBIT(curr_state, UNC_THRESH));
+ sprintf(thresh_name, "Upper Non Critical");
+ }
+ break;
+
+ case LNR_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = (SETBIT(curr_state, LNR_THRESH) |
+ SETBIT(curr_state, LCR_THRESH) |
+ SETBIT(curr_state, LNC_THRESH));
+ sprintf(thresh_name, "Lower Non Recoverable");
+ }
+ break;
+
+ case LCR_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = (SETBIT(curr_state, LCR_THRESH) |
+ SETBIT(curr_state, LNC_THRESH));
+ sprintf(thresh_name, "Lower Critical");
+ }
+ break;
+
+ case LNC_THRESH:
+ if (curr_val <= thresh_val) {
+ curr_state = (SETBIT(curr_state, LNC_THRESH));
+ sprintf(thresh_name, "Lower Non Critical");
+ }
+ break;
+
+ default:
+ syslog(LOG_ALERT, "get_snr_thresh_val: wrong thresh enum value");
+ exit(-1);
+ }
+
+ if (curr_state) {
+ curr_state &= snr[snr_num].flag;
+ snr[snr_num].curr_state |= curr_state;
+ syslog(LOG_CRIT, "ASSERT: %s threshold raised - FRU: %d, num: 0x%X,"
+ " snr: %-16s,",thresh_name, fru, snr_num, snr[snr_num].name);
+ syslog(LOG_CRIT, "curr_val: %.2f %s, thresh_val: %.2f %s cf: %u",
+ curr_val, snr[snr_num].units, thresh_val, snr[snr_num].units, snr[snr_num].curr_state);
+ }
+}
+
+/*
+ * Starts monitoring all the sensors on a fru for all the threshold values.
+ * Each pthread runs this monitoring for a different fru.
+ */
+static void *
+snr_monitor(void *arg) {
+
+ uint8_t fru = *(uint8_t *) arg;
+ int f, ret, snr_num;
+ float normal_val, curr_val;
+ thresh_sensor_t *snr;
+
+#ifdef TESTING
+ float temp_thresh;
+ int cnt = 0;
+#endif /* TESTING */
+
+ snr = get_struct_thresh_sensor(fru);
+ if (snr == NULL) {
+ syslog(LOG_ALERT, "snr_monitor: get_struct_thresh_sensor failed");
+ exit(-1);
+ }
+
+ while(1) {
+
+#ifdef TESTING
+ cnt++;
+#endif /* TESTING */
+
+ for (snr_num = 0; snr_num < MAX_SENSOR_NUM; snr_num++) {
+ curr_val = 0;
+ if (snr[snr_num].flag) {
+ if (!(ret = read_snr_val(fru, snr_num, &curr_val))) {
+
+
+#ifdef TESTING
+ /*
+ * The curr_val crosses UCR and then return to a state
+ * where UNC < curr_val < UCR and then eventually back to normal.
+ */
+ if (cnt == 5 && snr_num == BIC_SENSOR_MB_INLET_TEMP) {
+ snr[snr_num].flag |= SETBIT(snr[snr_num].flag, UNC_THRESH);
+ temp_thresh = snr[snr_num].ucr_thresh;
+ snr[snr_num].ucr_thresh = 20.0;
+ snr[snr_num].unc_thresh = 10.0;
+ } else if (cnt == 8 && snr_num == BIC_SENSOR_MB_INLET_TEMP) {
+ snr[snr_num].ucr_thresh = temp_thresh;
+ } else if (cnt == 10 && snr_num == BIC_SENSOR_MB_INLET_TEMP) {
+ snr[snr_num].unc_thresh = 50.0;
+ } else if (cnt == 11 && snr_num == BIC_SENSOR_MB_INLET_TEMP) {
+ snr[snr_num].unc_thresh = 0.0;
+ snr[snr_num].flag &= CLEARBIT(snr[snr_num].flag, UNC_THRESH);
+
+ }
+#endif /* TESTING */
+
+#ifdef DEBUG
+ if (cnt == 2) {
+ syslog(LOG_INFO, "pthread %d, cnt: %d, num: 0x%X name: %-16s"
+ " units:%s", fru, cnt, snr_num, snr[snr_num].name,
+ snr[snr_num].units);
+ }
+#endif /* DEBUG */
+
+ check_thresh_assert(fru, snr_num, UNR_THRESH, curr_val);
+ check_thresh_assert(fru, snr_num, UCR_THRESH, curr_val);
+ check_thresh_assert(fru, snr_num, UNC_THRESH, curr_val);
+ check_thresh_assert(fru, snr_num, LNR_THRESH, curr_val);
+ check_thresh_assert(fru, snr_num, LCR_THRESH, curr_val);
+ check_thresh_assert(fru, snr_num, LNC_THRESH, curr_val);
+
+ check_thresh_deassert(fru, snr_num, UNC_THRESH, curr_val);
+ check_thresh_deassert(fru, snr_num, UCR_THRESH, curr_val);
+ check_thresh_deassert(fru, snr_num, UNR_THRESH, curr_val);
+ check_thresh_deassert(fru, snr_num, LNC_THRESH, curr_val);
+ check_thresh_deassert(fru, snr_num, LCR_THRESH, curr_val);
+ check_thresh_deassert(fru, snr_num, LNR_THRESH, curr_val);
+
+ } else {
+ /*
+ * Incase the read_snr_val failed for a sensor,
+ * disable all the threshold checks for that sensor
+ * after logging an approciate syslog message.
+ */
+ if (ret) {
+ syslog(LOG_ERR, "FRU: %d, num: 0x%X, snr:%-16s, read failed",
+ fru, snr_num, snr[snr_num].name);
+ syslog(LOG_ERR, "FRU: %d, num: 0x%X, snr:%-16s, check disabled",
+ fru, snr_num, snr[snr_num].name);
+ snr[snr_num].flag = 0;
+ //}
+ }
+ } /* read_snr_val return check */
+ } /* flag check */
+ } /* loop for all sensors */
+ sleep(5);
+ } /* while loop*/
+} /* function definition */
+
+
+/* Spawns a pthread for each fru to monitor all the sensors on it */
+static void
+run_sensord(int argc, char **argv) {
+ int i, arg;
+
+ pthread_t thread_snr[MAX_NUM_FRUS];
+ int fru[MAX_NUM_FRUS] = {0};
+
+ for (arg = 1; arg < argc; arg ++) {
+#ifdef CONFIG_YOSEMITE
+ if (!(strcmp(argv[arg], "slot1")))
+ fru[FRU_SLOT1 - 1] = FRU_SLOT1;
+ else if (!(strcmp(argv[arg], "slot2")))
+ fru[FRU_SLOT2 - 1] = FRU_SLOT2;
+ else if (!(strcmp(argv[arg], "slot3")))
+ fru[FRU_SLOT3 - 1] = FRU_SLOT3;
+ else if (!(strcmp(argv[arg], "slot4")))
+ fru[FRU_SLOT4 - 1] = FRU_SLOT4;
+ else if (!(strcmp(argv[arg], "spb")))
+ fru[FRU_SPB - 1] = FRU_SPB;
+ else if (!(strcmp(argv[arg], "nic")))
+ fru[FRU_NIC - 1] = FRU_NIC;
+ else {
+ syslog(LOG_ALERT, "Wrong argument: %s", argv[arg]);
+ exit(1);
+ }
+#endif /* CONFIG_YOSEMITE */
+
+ }
+
+ for (i = 0; i < MAX_NUM_FRUS; i++) {
+ if (fru[i]) {
+ if (pthread_create(&thread_snr[i], NULL, snr_monitor,
+ (void*) &fru[i]) < 0) {
+ syslog(LOG_ALERT, "pthread_create for FRU %d failed\n", fru[i]);
+ }
+#ifdef DEBUG
+ else {
+ syslog(LOG_ALERT, "pthread_create for FRU %d succeed\n", fru[i]);
+ }
+#endif /* DEBUG */
+ }
+ sleep(1);
+ }
+
+ for (i = 0; i < MAX_NUM_FRUS; i++) {
+ if (fru[i])
+ pthread_join(thread_snr[i], NULL);
+ }
+}
+
+
+#ifdef DEBUG
+void print_snr_thread(uint8_t fru, thresh_sensor_t *snr)
+{
+ int i;
+ float curr_val;
+
+ for (i = 1; i <= MAX_SENSOR_NUM; i++) {
+ if (snr[i].flag) {
+ curr_val = 0;
+ if(!(read_snr_val(fru, i, &curr_val))) {
+ printf("%-30s:\t%.2f %s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
+ snr[i].name, curr_val,snr[i].units,
+ snr[i].ucr_thresh,
+ snr[i].unc_thresh,
+ snr[i].lcr_thresh,
+ snr[i].lnr_thresh,
+ snr[i].pos_hyst,
+ snr[i].neg_hyst);
+ } else
+ printf("Reading failed: %-16s\n", snr[i].name);
+ }
+ }
+}
+#endif /* DEBUG */
+
+int
+main(int argc, void **argv) {
+ int dev, rc, pid_file;
+
+ if (argc < 2) {
+ syslog(LOG_ALERT, "Usage: sensord <options>");
+ printf("Usage: sensord <options>\n");
+#ifdef CONFIG_YOSEMITE
+ syslog(LOG_ALERT, "Options: [slot1 | slot2 | slot3 | slot4 | spb | nic]");
+ printf("Options: [slot1 | slot2 | slot3 | slot4 | spb | nic]\n");
+#endif /* CONFIG_YOSEMITE */
+ exit(1);
+ }
+
+ pid_file = open("/var/run/sensord.pid", O_CREAT | O_RDWR, 0666);
+ rc = flock(pid_file, LOCK_EX | LOCK_NB);
+ if(rc) {
+ if(EWOULDBLOCK == errno) {
+ printf("Another sensord instance is running...\n");
+ exit(-1);
+ }
+ } else {
+
+#ifdef CONFIG_YOSEMITE
+ read_snr_val = &yosemite_sensor_read;
+#endif /* CONFIG_YOSEMITE */
+
+ init_all_snr_thresh();
+
+#ifdef DEBUG
+ print_snr_thread(1, snr_slot1);
+ print_snr_thread(2, snr_slot2);
+ print_snr_thread(3, snr_slot3);
+ print_snr_thread(4, snr_slot4);
+#endif /* DEBUG */
+
+ daemon(0,1);
+ openlog("sensord", LOG_CONS, LOG_DAEMON);
+ syslog(LOG_INFO, "sensord: daemon started");
+ run_sensord(argc, (char **) argv);
+ }
+
+ return 0;
+}
diff --git a/common/recipes-core/sensor-mon/sensor-mon_0.1.bb b/common/recipes-core/sensor-mon/sensor-mon_0.1.bb
new file mode 100644
index 0000000..adbd4cb
--- /dev/null
+++ b/common/recipes-core/sensor-mon/sensor-mon_0.1.bb
@@ -0,0 +1,58 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "Sensor Monitoring Daemon"
+DESCRIPTION = "Daemon for monitoring the sensors"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://sensord.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238"
+
+SRC_URI = "file://Makefile \
+ file://sensord.c \
+ "
+
+S = "${WORKDIR}"
+
+binfiles = "sensord \
+ "
+
+CFLAGS += " -lsdr "
+
+DEPENDS += " libsdr "
+
+pkgdir = "sensor-mon"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ for f in ${binfiles}; do
+ install -m 755 $f ${dst}/$f
+ ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
+ done
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/sensor-mon ${prefix}/local/bin"
+
+# Inhibit complaints about .debug directories for the sensord binary:
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/sensor-util/files/Makefile b/common/recipes-core/sensor-util/files/Makefile
new file mode 100644
index 0000000..2d39a04
--- /dev/null
+++ b/common/recipes-core/sensor-util/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: sensor-util
+
+
+sensor-util: sensor-util.o
+ $(CC) $(CFLAGS) -lpal -lrt -lm -std=gnu99 -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o sensor-util
diff --git a/common/recipes-core/sensor-util/files/sensor-util.c b/common/recipes-core/sensor-util/files/sensor-util.c
new file mode 100644
index 0000000..eb38d65
--- /dev/null
+++ b/common/recipes-core/sensor-util/files/sensor-util.c
@@ -0,0 +1,173 @@
+/*
+ * yosemite-sensors
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <openbmc/pal.h>
+
+static int
+print_usage() {
+ printf("Usage: sensor-util [ %s ] <sensor num>\n"
+ "sensor num is optional.", pal_fru_list);
+}
+
+static void
+print_single_sensor_reading(uint8_t fru, uint8_t *sensor_list, int sensor_cnt, uint8_t num) {
+
+ int i;
+ float fvalue;
+ char name[24];
+ char units[64];
+ int ret = 0;
+
+ for (i = 0; i < sensor_cnt; i++) {
+
+ if (sensor_list[i] == num) {
+ ret = 1;
+ pal_get_sensor_name(fru, sensor_list[i], name);
+ pal_get_sensor_units(fru, sensor_list[i], units);
+
+ if (pal_sensor_read(fru, sensor_list[i], &fvalue) < 0) {
+
+ printf("pal_sensor_read failed: fru: %d num: 0x%X name: %-23s\n",
+ fru, sensor_list[i], name);
+ } else {
+ printf("%-23s: %.2f %s\n", name, fvalue, units);
+ }
+
+ break;
+ }
+ }
+
+ if (!ret) {
+ printf("Wrong sensor number!\n");
+ print_usage();
+ exit(-1);
+ }
+}
+
+static void
+print_sensor_reading(uint8_t fru, uint8_t *sensor_list, int sensor_cnt) {
+
+ int i;
+ float fvalue;
+ char name[24];
+ char units[64];
+
+ for (i = 0; i < sensor_cnt; i++) {
+
+ /* Clear the variable */
+ sprintf(name, "");
+ sprintf(units, "");
+
+ pal_get_sensor_name(fru, sensor_list[i], name);
+ pal_get_sensor_units(fru, sensor_list[i], units);
+
+ if (pal_sensor_read(fru, sensor_list[i], &fvalue) < 0) {
+
+ printf("pal_sensor_read failed: fru: %d num: 0x%X name: %-23s\n",
+ fru, sensor_list[i], name);
+ } else {
+ printf("%-23s: %.2f %s\n", name, fvalue, units);
+ }
+ }
+}
+
+int
+main(int argc, char **argv) {
+
+ int ret;
+ int sensor_cnt;
+ uint8_t *sensor_list;
+ uint8_t fru;
+ uint8_t num;
+
+ if (argc < 2 || argc > 3) {
+ print_usage();
+ exit(-1);
+ }
+
+ if (argc == 3) {
+ errno = 0;
+ num = (uint8_t) strtol(argv[2], NULL, 0);
+ if (errno) {
+ printf("Sensor number format incorrect.\n");
+ print_usage();
+ exit(-1);
+ }
+ }
+
+
+ ret = pal_get_fru_id(argv[1], &fru);
+ if (ret < 0) {
+ print_usage();
+ return ret;
+ }
+
+ if (fru == 0) {
+ fru = 1;
+ while (fru <= MAX_NUM_FRUS) {
+
+ if (fru == FRU_NIC) {
+ printf("\nsensor-util does not support nic\n");
+ exit(-1);
+ }
+
+ ret = pal_get_fru_sensor_list(fru, &sensor_list, &sensor_cnt);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (num) {
+ print_single_sensor_reading(fru, sensor_list, sensor_cnt, num);
+ } else {
+ print_sensor_reading(fru, sensor_list, sensor_cnt);
+ }
+
+ fru++;
+ printf("\n");
+ }
+ } else {
+
+ if (fru == FRU_NIC) {
+ printf("\nsensor-util does not support nic\n");
+ //exit(-1);
+ }
+
+ ret = pal_get_fru_sensor_list(fru, &sensor_list, &sensor_cnt);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (num) {
+ print_single_sensor_reading(fru, sensor_list, sensor_cnt, num);
+ } else {
+ print_sensor_reading(fru, sensor_list, sensor_cnt);
+ }
+ }
+
+ return 0;
+}
diff --git a/common/recipes-core/sensor-util/sensor-util_0.1.bb b/common/recipes-core/sensor-util/sensor-util_0.1.bb
new file mode 100644
index 0000000..227ec53
--- /dev/null
+++ b/common/recipes-core/sensor-util/sensor-util_0.1.bb
@@ -0,0 +1,34 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "Sensor Utility"
+DESCRIPTION = "Util for reading various sensors"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://sensor-util.c;beginline=4;endline=16;md5=b395943ba8a0717a83e62ca123a8d238"
+
+SRC_URI = "file://Makefile \
+ file://sensor-util.c \
+ "
+S = "${WORKDIR}"
+
+binfiles = "sensor-util"
+
+DEPENDS =+ " libpal "
+
+pkgdir = "sensor-util"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ install -m 755 sensor-util ${dst}/sensor-util
+ ln -snf ../fbpackages/${pkgdir}/sensor-util ${bin}/sensor-util
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/sensor-util ${prefix}/local/bin"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-core/watchdog-ctrl/watchdog-ctrl_0.1.bb b/common/recipes-core/watchdog-ctrl/watchdog-ctrl_0.1.bb
index 00cf0f9..14c0fee 100644
--- a/common/recipes-core/watchdog-ctrl/watchdog-ctrl_0.1.bb
+++ b/common/recipes-core/watchdog-ctrl/watchdog-ctrl_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Watchdog control utilities."
DESCRIPTION = "The utilities to control system watchdog."
SECTION = "base"
diff --git a/common/recipes-lib/fruid/files/Makefile b/common/recipes-lib/fruid/files/Makefile
new file mode 100644
index 0000000..225d5f7
--- /dev/null
+++ b/common/recipes-lib/fruid/files/Makefile
@@ -0,0 +1,27 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+lib: libfruid.so
+
+libfruid.so: fruid.c
+ $(CC) $(CFLAGS) -fPIC -c -o fruid.o fruid.c
+ $(CC) -shared -o libfruid.so fruid.o -lc
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o libfruid.so
diff --git a/common/recipes-lib/fruid/files/fruid.c b/common/recipes-lib/fruid/files/fruid.c
new file mode 100644
index 0000000..dc71ac8
--- /dev/null
+++ b/common/recipes-lib/fruid/files/fruid.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include "fruid.h"
+
+#define FIELD_TYPE(x) ((x & (0x03 << 6)) >> 6)
+#define FIELD_LEN(x) (x & ~(0x03 << 6))
+#define FIELD_EMPTY "N/A"
+
+/* Unix time difference between 1970 and 1996. */
+#define UNIX_TIMESTAMP_1996 820454400
+
+/* Array for BCD Plus definition. */
+const char bcd_plus_array[] = "0123456789 -.XXX";
+
+/* Array for 6-Bit ASCII definition. */
+const char * ascii_6bit[4] = {
+ " !\"#$%&'()*+,-./",
+ "0123456789:;<=>?",
+ "@ABCDEFGHIJKLMNO",
+ "PQRSTUVWXYZ[\\]^_"
+};
+
+/*
+ * calculate_time - calculate time from the unix time stamp stored
+ *
+ * @mfg_time : Unix timestamp since 1996
+ *
+ * returns char * for mfg_time_str
+ * returns NULL for memory allocation failure
+ */
+static char * calculate_time(uint8_t * mfg_time)
+{
+ int len;
+ struct tm * local;
+ time_t unix_time = 0;
+ unix_time = ((mfg_time[2] << 16) + (mfg_time[1] << 8) + mfg_time[0]) * 60;
+ unix_time += UNIX_TIMESTAMP_1996;
+
+ local = localtime(&unix_time);
+ char * str = asctime(local);
+
+ len = strlen(str);
+
+ char * mfg_time_str = (char *) malloc(len);
+ if (!mfg_time_str) {
+ syslog(LOG_ALERT, "fruid: malloc: memory allocation failed\n");
+ return NULL;
+ }
+
+ memset(mfg_time_str, 0, len);
+
+ memcpy(mfg_time_str, str, len);
+
+ mfg_time_str[len - 1] = '\0';
+
+ return mfg_time_str;
+}
+
+/*
+ * verify_chksum - verify the zero checksum of the data
+ *
+ * @area : offset of the area
+ * @len : len of the area in bytes
+ * @chksum_read : stored checksum in the data.
+ *
+ * returns 0 if chksum is verified
+ * returns -1 if there exist a mismatch
+ */
+static int verify_chksum(uint8_t * area, uint8_t len, uint8_t chksum_read)
+{
+ int i;
+ uint8_t chksum = 0;
+
+ for (i = 0; i < len - 1; i++)
+ chksum += area[i];
+
+ /* Zero checksum calculation */
+ chksum = ~(chksum) + 1;
+
+ return (chksum == chksum_read) ? 0 : -1;
+}
+
+/*
+ * get_chassis_type - get the Chassis type
+ *
+ * @type_hex : type stored in the data
+ *
+ * returns char ptr for chassis type string
+ * returns NULL if type not in the list
+ */
+static char * get_chassis_type(uint8_t type_hex)
+{
+ int type, ret;
+ char type_int[4];
+
+ ret = sprintf(type_int, "%u", type_hex);
+ type = atoi(type_int) - 1;
+
+ /* If the type is not in the list defined.*/
+ if (type > FRUID_CHASSIS_TYPECODE_MAX || type < FRUID_CHASSIS_TYPECODE_MIN) {
+ syslog(LOG_INFO, "fruid: chassis area: invalid chassis type\n");
+ return NULL;
+ }
+
+ char * type_str = (char *) malloc(strlen(fruid_chassis_type[type]));
+ if (!type_str) {
+ syslog(LOG_ALERT, "fruid: malloc: memory allocation failed\n");
+ return NULL;
+ }
+
+ memcpy(type_str, fruid_chassis_type[type], strlen(fruid_chassis_type[type]));
+
+ return type_str;
+}
+
+/*
+ * _fruid_area_field_read - read the field data
+ *
+ * @offset : offset of the field
+ *
+ * returns char ptr for the field data string
+ */
+static char * _fruid_area_field_read(uint8_t *offset)
+{
+ int field_type, field_len, field_len_eff;
+ int idx, idx_eff, val;
+ char * field;
+
+ /* Bits 7:6 */
+ field_type = FIELD_TYPE(offset[0]);
+ /* Bits 5:0 */
+ field_len = FIELD_LEN(offset[0]);
+
+ /* Calculate the effective length of the field data based on type stored. */
+ switch (field_type) {
+
+ case TYPE_BINARY:
+ /* TODO: Need to add support to read data stored in binary type. */
+ field_len_eff = 1;
+ break;
+
+ case TYPE_ASCII_6BIT:
+ /*
+ * Every 3 bytes have four 6-bit packed values
+ * + 6-bit values from the remaining field bytes.
+ */
+ field_len_eff = (field_len / 3) * 4 + (field_len % 3);
+ break;
+
+ case TYPE_BCD_PLUS:
+ case TYPE_ASCII_8BIT:
+ field_len_eff = field_len;
+ break;
+ }
+
+ /* If field data is zero, store 'N/A' for that field. */
+ field_len_eff > 0 ? (field = (char *) malloc(field_len_eff + 1)) :
+ (field = (char *) malloc(strlen(FIELD_EMPTY)));
+ if (!field) {
+ syslog(LOG_ALERT, "fruid: malloc: memory allocation failed\n");
+ return NULL;
+ }
+
+ memset(field, 0, field_len + 1);
+
+ if (field_len_eff < 1) {
+ strcpy(field, FIELD_EMPTY);
+ return field;
+ }
+
+ /* Retrieve field data depending on the type it was stored. */
+ switch (field_type) {
+ case TYPE_BINARY:
+ /* TODO: Need to add support to read data stored in binary type. */
+ break;
+
+ case TYPE_BCD_PLUS:
+
+ idx = 0;
+ while (idx != field_len) {
+ field[idx] = bcd_plus_array[offset[idx + 1] & 0x0F];
+ idx++;
+ }
+ field[idx] = '\0';
+ break;
+
+ case TYPE_ASCII_6BIT:
+
+ idx_eff = 0, idx = 1;
+
+ while (field_len > 0) {
+
+ /* 6-Bits => Bits 5:0 of the first byte */
+ val = offset[idx] & 0x3F;
+ field[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+ field_len--;
+
+ if (field_len > 0) {
+ /* 6-Bits => Bits 3:0 of second byte + Bits 7:6 of first byte. */
+ val = ((offset[idx] & 0xC0) >> 6) |
+ ((offset[idx + 1] & 0x0F) << 2);
+ field[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+ field_len--;
+ }
+
+ if (field_len > 0) {
+ /* 6-Bits => Bits 1:0 of third byte + Bits 7:4 of second byte. */
+ val = ((offset[idx + 1] & 0xF0) >> 4) |
+ ((offset[idx + 2] & 0x03) << 4);
+ field[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+
+ /* 6-Bits => Bits 7:2 of third byte. */
+ val = ((offset[idx + 2] & 0xFC) >> 2);
+ field[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+
+ field_len--;
+ idx += 3;
+ }
+ }
+ /* Add Null terminator */
+ field[idx_eff] = '\0';
+ break;
+
+ case TYPE_ASCII_8BIT:
+
+ memcpy(field, offset + 1, field_len);
+ /* Add Null terminator */
+ field[field_len] = '\0';
+ break;
+ }
+
+ return field;
+}
+
+/* Free all the memory allocated for fruid information */
+void free_fruid_info(fruid_info_t * fruid)
+{
+ if (fruid->chassis.flag) {
+ free(fruid->chassis.type_str);
+ free(fruid->chassis.part);
+ free(fruid->chassis.serial);
+ free(fruid->chassis.custom);
+ }
+
+ if (fruid->board.flag) {
+ free(fruid->board.mfg_time_str);
+ free(fruid->board.mfg);
+ free(fruid->board.name);
+ free(fruid->board.serial);
+ free(fruid->board.part);
+ free(fruid->board.fruid);
+ }
+
+ if (fruid->product.flag) {
+ free(fruid->board.custom);
+ free(fruid->product.mfg);
+ free(fruid->product.name);
+ free(fruid->product.part);
+ free(fruid->product.version);
+ free(fruid->product.serial);
+ free(fruid->product.asset_tag);
+ free(fruid->product.fruid);
+ free(fruid->product.custom);
+ }
+}
+
+/* Initialize the fruid information struct */
+static void init_fruid_info(fruid_info_t * fruid)
+{
+ fruid->chassis.flag = 0;
+ fruid->board.flag = 0;
+ fruid->product.flag = 0;
+ fruid->chassis.type_str = NULL;
+ fruid->chassis.part = NULL;
+ fruid->chassis.serial = NULL;
+ fruid->chassis.custom = NULL;
+ fruid->board.mfg_time_str = NULL;
+ fruid->board.mfg = NULL;
+ fruid->board.name = NULL;
+ fruid->board.serial = NULL;
+ fruid->board.part = NULL;
+ fruid->board.fruid = NULL;
+ fruid->board.custom = NULL;
+ fruid->product.mfg = NULL;
+ fruid->product.name = NULL;
+ fruid->product.part = NULL;
+ fruid->product.version = NULL;
+ fruid->product.serial = NULL;
+ fruid->product.asset_tag = NULL;
+ fruid->product.fruid = NULL;
+ fruid->product.custom = NULL;
+}
+
+/* Parse the Product area data */
+int parse_fruid_area_product(uint8_t * product,
+ fruid_area_product_t * fruid_product)
+{
+ int ret, index;
+
+ index = 0;
+
+ /* Reset the struct to zero */
+ memset(fruid_product, 0, sizeof(fruid_area_product_t));
+
+ /* Check if the format version is as per IPMI FRUID v1.0 format spec */
+ fruid_product->format_ver = product[index++];
+ if (fruid_product->format_ver != FRUID_FORMAT_VER) {
+ syslog(LOG_ERR, "fruid: product_area: format version not supported");
+ return EPROTONOSUPPORT;
+ }
+
+ fruid_product->area_len = product[index++] * FRUID_AREA_LEN_MULTIPLIER;
+ fruid_product->lang_code = product[index++];
+
+ fruid_product->chksum = product[fruid_product->area_len - 1];
+ ret = verify_chksum((uint8_t *) product,
+ fruid_product->area_len, fruid_product->chksum);
+
+ if (ret) {
+ syslog(LOG_ERR, "fruid: product_area: chksum not verified.");
+ return EBADF;
+ }
+
+ fruid_product->mfg = _fruid_area_field_read(&product[index]);
+ if (fruid_product->mfg == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->name = _fruid_area_field_read(&product[index]);
+ if (fruid_product->name == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->part = _fruid_area_field_read(&product[index]);
+ if (fruid_product->part == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->version = _fruid_area_field_read(&product[index]);
+ if (fruid_product->version == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->serial = _fruid_area_field_read(&product[index]);
+ if (fruid_product->serial == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->asset_tag = _fruid_area_field_read(&product[index]);
+ if (fruid_product->asset_tag == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->fruid = _fruid_area_field_read(&product[index]);
+ if (fruid_product->fruid == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ fruid_product->custom = _fruid_area_field_read(&product[index]);
+ if (fruid_product->custom == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(product[index]) + 1;
+
+ return 0;
+}
+
+/* Parse the Board area data */
+int parse_fruid_area_board(uint8_t * board,
+ fruid_area_board_t * fruid_board)
+{
+ int ret, index, i;
+ time_t unix_time;
+
+ index = 0;
+
+ /* Reset the struct to zero */
+ memset(fruid_board, 0, sizeof(fruid_area_board_t));
+
+ /* Check if the format version is as per IPMI FRUID v1.0 format spec */
+ fruid_board->format_ver = board[index++];
+ if (fruid_board->format_ver != FRUID_FORMAT_VER) {
+ syslog(LOG_ERR, "fruid: board_area: format version not supported");
+ return EPROTONOSUPPORT;
+ }
+ fruid_board->area_len = board[index++] * FRUID_AREA_LEN_MULTIPLIER;
+ fruid_board->lang_code = board[index++];
+
+ fruid_board->chksum = board[fruid_board->area_len - 1];
+ ret = verify_chksum((uint8_t *) board,
+ fruid_board->area_len, fruid_board->chksum);
+
+ if (ret) {
+ syslog(LOG_ERR, "fruid: board_area: chksum not verified.");
+ return EBADF;
+ }
+
+ for (i = 0; i < 3; i++) {
+ fruid_board->mfg_time[i] = board[index++];
+ }
+
+ fruid_board->mfg_time_str = calculate_time(fruid_board->mfg_time);
+ if (fruid_board->mfg_time_str == NULL)
+ return ENOMEM;
+
+ fruid_board->mfg = _fruid_area_field_read(&board[index]);
+ if (fruid_board->mfg == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ fruid_board->name = _fruid_area_field_read(&board[index]);
+ if (fruid_board->name == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ fruid_board->serial = _fruid_area_field_read(&board[index]);
+ if (fruid_board->serial == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ fruid_board->part = _fruid_area_field_read(&board[index]);
+ if (fruid_board->part == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ fruid_board->fruid = _fruid_area_field_read(&board[index]);
+ if (fruid_board->fruid == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ fruid_board->custom = _fruid_area_field_read(&board[index]);
+ if (fruid_board->custom == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(board[index]) + 1;
+
+ return 0;
+}
+
+/* Parse the Chassis area data */
+int parse_fruid_area_chassis(uint8_t * chassis,
+ fruid_area_chassis_t * fruid_chassis)
+{
+ int ret, index;
+
+ index = 0;
+
+ /* Reset the struct to zero */
+ memset(fruid_chassis, 0, sizeof(fruid_area_chassis_t));
+
+ /* Check if the format version is as per IPMI FRUID v1.0 format spec */
+ fruid_chassis->format_ver = chassis[index++];
+ if (fruid_chassis->format_ver != FRUID_FORMAT_VER) {
+ syslog(LOG_ERR, "fruid: chassis_area: format version not supported");
+ return EPROTONOSUPPORT;
+ }
+
+ fruid_chassis->area_len = chassis[index++] * FRUID_AREA_LEN_MULTIPLIER;
+ fruid_chassis->type = chassis[index++];
+
+ fruid_chassis->chksum = chassis[fruid_chassis->area_len - 1];
+ ret = verify_chksum((uint8_t *) chassis,
+ fruid_chassis->area_len, fruid_chassis->chksum);
+ if (ret) {
+ syslog(LOG_ERR, "fruid: chassis_area: chksum not verified.");
+ return EBADF;
+ }
+
+ fruid_chassis->type_str = get_chassis_type(fruid_chassis->type);
+ if (fruid_chassis->type_str == NULL)
+ return ENOMSG;
+
+ fruid_chassis->part = _fruid_area_field_read(&chassis[index]);
+ if (fruid_chassis->part == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(chassis[index]) + 1;
+
+ fruid_chassis->serial = _fruid_area_field_read(&chassis[index]);
+ if (fruid_chassis->serial == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(chassis[index]) + 1;
+
+ fruid_chassis->custom = _fruid_area_field_read(&chassis[index]);
+ if (fruid_chassis->custom == NULL)
+ return ENOMEM;
+ index += FIELD_LEN(chassis[index]) + 1;
+
+ return 0;
+}
+
+/* Calculate the area offsets and populate the fruid_eeprom_t struct */
+void set_fruid_eeprom_offsets(uint8_t * eeprom, fruid_header_t * header,
+ fruid_eeprom_t * fruid_eeprom)
+{
+ fruid_eeprom->header = eeprom + 0x00;
+
+ header->offset_area.chassis ? (fruid_eeprom->chassis = eeprom + \
+ (header->offset_area.chassis * FRUID_OFFSET_MULTIPLIER)) : \
+ (fruid_eeprom->chassis = NULL);
+
+ header->offset_area.board ? (fruid_eeprom->board = eeprom + \
+ (header->offset_area.board * FRUID_OFFSET_MULTIPLIER)) : \
+ (fruid_eeprom->board = NULL);
+
+ header->offset_area.product ? (fruid_eeprom->product = eeprom + \
+ (header->offset_area.product * FRUID_OFFSET_MULTIPLIER)) : \
+ (fruid_eeprom->product = NULL);
+
+ header->offset_area.multirecord ? (fruid_eeprom->multirecord = eeprom + \
+ (header->offset_area.multirecord * FRUID_OFFSET_MULTIPLIER)) : \
+ (fruid_eeprom->multirecord = NULL);
+}
+
+/* Populate the common header struct */
+int parse_fruid_header(uint8_t * eeprom, fruid_header_t * header)
+{
+ int ret;
+
+ memcpy((uint8_t *)header, (uint8_t *)eeprom, sizeof(fruid_header_t));
+ ret = verify_chksum((uint8_t *) header,
+ sizeof(fruid_header_t), header->chksum);
+ if (ret) {
+ syslog(LOG_ERR, "fruid: common_header: chksum not verified.");
+ return EBADF;
+ }
+
+ return ret;
+}
+
+/* Parse the eeprom dump and populate the fruid info in struct */
+int populate_fruid_info(fruid_eeprom_t * fruid_eeprom, fruid_info_t * fruid)
+{
+ int ret;
+
+ /* Initial all the required fruid structures */
+ fruid_area_chassis_t fruid_chassis;
+ fruid_area_board_t fruid_board;
+ fruid_area_product_t fruid_product;
+
+ /* If Chassis area is present, parse and print it */
+ if (fruid_eeprom->chassis) {
+ ret = parse_fruid_area_chassis(fruid_eeprom->chassis, &fruid_chassis);
+ if (!ret) {
+ fruid->chassis.flag = 1;
+ fruid->chassis.type_str = fruid_chassis.type_str;
+ fruid->chassis.part = fruid_chassis.part;
+ fruid->chassis.serial = fruid_chassis.serial;
+ fruid->chassis.custom = fruid_chassis.custom;
+ } else
+ return ret;
+ }
+
+ /* If Board area is present, parse and print it */
+ if (fruid_eeprom->board) {
+ ret = parse_fruid_area_board(fruid_eeprom->board, &fruid_board);
+ if (!ret) {
+ fruid->board.flag = 1;
+ fruid->board.mfg_time_str = fruid_board.mfg_time_str;
+ fruid->board.mfg = fruid_board.mfg;
+ fruid->board.name = fruid_board.name;
+ fruid->board.serial = fruid_board.serial;
+ fruid->board.part = fruid_board.part;
+ fruid->board.fruid = fruid_board.fruid;
+ fruid->board.custom = fruid_board.custom;
+ } else
+ return ret;
+ }
+
+ /* If Product area is present, parse and print it */
+ if (fruid_eeprom->product) {
+ ret = parse_fruid_area_product(fruid_eeprom->product, &fruid_product);
+ if (!ret) {
+ fruid->product.flag = 1;
+ fruid->product.mfg = fruid_product.mfg;
+ fruid->product.name = fruid_product.name;
+ fruid->product.part = fruid_product.part;
+ fruid->product.version = fruid_product.version;
+ fruid->product.serial = fruid_product.serial;
+ fruid->product.asset_tag = fruid_product.asset_tag;
+ fruid->product.fruid = fruid_product.fruid;
+ fruid->product.custom = fruid_product.custom;
+ } else
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * fruid_parse - To parse the bin file (eeprom) and populate
+ * the fruid information in the struct
+ * @bin : Eeprom binary file
+ * @fruid : ptr to the struct that holds the fruid information
+ *
+ * returns 0 on success
+ * returns non-zero errno value on error
+ */
+int fruid_parse(const char * bin, fruid_info_t * fruid)
+{
+ int fruid_len, ret;
+ FILE *fruid_fd;
+ uint8_t * eeprom;
+
+ /* Initial all the required fruid structures */
+ fruid_header_t fruid_header;
+ fruid_eeprom_t fruid_eeprom;
+
+ memset(&fruid_header, 0, sizeof(fruid_header_t));
+ memset(&fruid_eeprom, 0, sizeof(fruid_eeprom_t));
+
+ /* Reset parser return value */
+ ret = 0;
+
+ /* Open the FRUID binary file */
+ fruid_fd = fopen(bin, "rb");
+ if (!fruid_fd) {
+ syslog(LOG_ERR, "fruid: unable to open the file");
+ return ENOENT;
+ }
+
+ /* Get the size of the binary file */
+ fseek(fruid_fd, 0, SEEK_END);
+ fruid_len = (uint32_t) ftell(fruid_fd);
+
+ fseek(fruid_fd, 0, SEEK_SET);
+
+ eeprom = (uint8_t *) malloc(fruid_len);
+ if (!eeprom) {
+ syslog(LOG_ALERT, "fruid: malloc: memory allocation failed\n");
+ return ENOMEM;
+ }
+
+ /* Read the binary file */
+ fread(eeprom, sizeof(uint8_t), fruid_len, fruid_fd);
+
+ /* Close the FRUID binary file */
+ fclose(fruid_fd);
+
+ /* Parse the common header data */
+ ret = parse_fruid_header(eeprom, &fruid_header);
+ if (ret) {
+ /* Free the eeprom malloc'ed memory */
+ free(eeprom);
+ return ret;
+ }
+
+ /* Calculate all the area offsets */
+ set_fruid_eeprom_offsets(eeprom, &fruid_header, &fruid_eeprom);
+
+ init_fruid_info(fruid);
+ /* Parse the eeprom and populate the fruid information */
+ ret = populate_fruid_info(&fruid_eeprom, fruid);
+ if (ret) {
+ /* Free the malloced memory for the fruid information */
+ free_fruid_info(fruid);
+ }
+
+ /* Free the eeprom malloced memory */
+ free(eeprom);
+
+ return ret;
+}
diff --git a/common/recipes-lib/fruid/files/fruid.h b/common/recipes-lib/fruid/files/fruid.h
new file mode 100644
index 0000000..713658d
--- /dev/null
+++ b/common/recipes-lib/fruid/files/fruid.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FRUID_H__
+#define __FRUID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <openbmc/ipmi.h>
+
+#define FRUID_FORMAT_VER 0x01
+#define FRUID_OFFSET_MULTIPLIER 8
+#define FRUID_AREA_LEN_MULTIPLIER 8
+
+#define FRUID_OFFSET_AREA_INTERNAL 0
+#define FRUID_OFFSET_AREA_CHASSIS 1
+#define FRUID_OFFSET_AREA_BOARD 2
+#define FRUID_OFFSET_AREA_PRODUCT 3
+#define FRUID_OFFSET_AREA_MULTIRECORD 4
+
+#define FRUID_CHASSIS_TYPECODE_MIN 1
+#define FRUID_CHASSIS_TYPECODE_MAX 32
+
+/* To hold the common header information. */
+typedef struct fruid_header_t {
+ uint8_t format_ver : 4;
+ struct {
+ uint8_t internal;
+ uint8_t chassis;
+ uint8_t board;
+ uint8_t product;
+ uint8_t multirecord;
+ } offset_area;
+ uint8_t pad;
+ uint8_t chksum;
+} fruid_header_t;
+
+/* To hold the Chassis area information. */
+typedef struct fruid_area_chassis_t {
+ uint8_t format_ver : 4;
+ uint8_t area_len;
+ uint8_t type;
+ char * type_str;
+ char * part;
+ char * serial;
+ char * custom;
+ uint8_t chksum;
+} fruid_area_chassis_t;
+
+/* To hold the Board area information. */
+typedef struct fruid_area_board_t {
+ uint8_t format_ver : 4;
+ uint8_t area_len;
+ uint8_t lang_code;
+ uint8_t mfg_time[3];
+ char * mfg_time_str;
+ char * mfg;
+ char * name;
+ char * serial;
+ char * part;
+ char * fruid;
+ char * custom;
+ uint8_t chksum;
+} fruid_area_board_t;
+
+/* To hold the Product area information. */
+typedef struct fruid_area_product_t {
+ uint8_t format_ver : 4;
+ uint8_t area_len;
+ uint8_t lang_code;
+ char * mfg;
+ char * name;
+ char * part;
+ char * version;
+ char * serial;
+ char * asset_tag;
+ char * fruid;
+ char * custom;
+ uint8_t chksum;
+} fruid_area_product_t;
+
+/* To hold the Multirecord area information. */
+typedef struct fruid_area_multirecord_t {
+ uint8_t format_ver : 4;
+ uint8_t area_len;
+ /* TODO: Add more fields to support Multirecord area. */
+} fruid_area_multirecord_t;
+
+/* To hold all the fruid information */
+typedef struct fruid_info_t {
+ struct {
+ uint8_t flag;
+ char * type_str;
+ char * part;
+ char * serial;
+ char * custom;
+ } chassis;
+ struct {
+ uint8_t flag;
+ char * mfg_time_str;
+ char * mfg;
+ char * name;
+ char * serial;
+ char * part;
+ char * fruid;
+ char * custom;
+ } board;
+ struct {
+ uint8_t flag;
+ char * mfg;
+ char * name;
+ char * part;
+ char * version;
+ char * serial;
+ char * asset_tag;
+ char * fruid;
+ char * custom;
+ } product;
+} fruid_info_t;
+
+/* To hold the different area offsets. */
+typedef struct fruid_eeprom_t {
+ uint8_t * header;
+ uint8_t * chassis;
+ uint8_t * board;
+ uint8_t * product;
+ uint8_t * multirecord;
+} fruid_eeprom_t;
+
+/* List of all the Chassis types. */
+const char * fruid_chassis_type [] = {
+ "Other", /* 0x01 */
+ "Unknown", /* 0x02 */
+ "Desktop", /* 0x03 */
+ "Low Profile Desktop", /* 0x04 */
+ "Pizza Box", /* 0x05 */
+ "Mini Tower", /* 0x06 */
+ "Tower", /* 0x07 */
+ "Portable", /* 0x08 */
+ "Laptop", /* 0x09 */
+ "Notebook", /* 0x0A */
+ "Hand Held", /* 0x0B */
+ "Docking Station", /* 0x0C */
+ "All in One", /* 0x0D */
+ "Sub Notebook", /* 0x0E */
+ "Space-saving", /* 0x0F */
+ "Lunch Box", /* 0x10 */
+ "Main Server Chassis", /* 0x11 */
+ "Expansion Chassis", /* 0x12 */
+ "SubChassis", /* 0x13 */
+ "Bus Expansion Chassis", /* 0x14 */
+ "Peripheral Chassis", /* 0x15 */
+ "RAID Chassis", /* 0x16 */
+ "Rack Mount Chassis", /* 0x17 */
+ "Sealed-case PC", /* 0x18 */
+ "Multi-system Chassis", /* 0x19 */
+ "Compact PCI", /* 0x1A */
+ "Advanced TCA", /* 0x1B */
+ "Blade", /* 0x1C */
+ "Blade Enclosure", /* 0x1D */
+ "Tablet", /* 0x1E */
+ "Convertible", /* 0x1F */
+ "Detachable" /* 0x20 */
+};
+
+int fruid_parse(const char * bin, fruid_info_t * fruid);
+void free_fruid_info(fruid_info_t * fruid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FRUID_H__ */
diff --git a/common/recipes-lib/fruid/libfruid_0.1.bb b/common/recipes-lib/fruid/libfruid_0.1.bb
new file mode 100644
index 0000000..7984d3b
--- /dev/null
+++ b/common/recipes-lib/fruid/libfruid_0.1.bb
@@ -0,0 +1,43 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "IPMI FRUID Library"
+DESCRIPTION = "library for ipmi fruid"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://fruid.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://Makefile \
+ file://fruid.c \
+ file://fruid.h \
+ "
+
+S = "${WORKDIR}"
+
+DEPENDS += " libipmi "
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 libfruid.so ${D}${libdir}/libfruid.so
+
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 fruid.h ${D}${includedir}/openbmc/fruid.h
+}
+
+FILES_${PN} = "${libdir}/libfruid.so"
+FILES_${PN}-dev = "${includedir}/openbmc/fruid.h"
diff --git a/common/recipes-lib/gpio/files/src/Makefile b/common/recipes-lib/gpio/files/src/Makefile
new file mode 100644
index 0000000..0b605fc
--- /dev/null
+++ b/common/recipes-lib/gpio/files/src/Makefile
@@ -0,0 +1,27 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+lib: libgpio.so
+
+libgpio.so: gpio.c
+ $(CC) $(CFLAGS) -fPIC -c -o gpio.o gpio.c
+ $(CC) -shared -o libgpio.so gpio.o -lc
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o libgpio.so
diff --git a/common/recipes-lib/gpio/files/src/gpio.c b/common/recipes-lib/gpio/files/src/gpio.c
new file mode 100644
index 0000000..9c1f7a2
--- /dev/null
+++ b/common/recipes-lib/gpio/files/src/gpio.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+//#define DEBUG
+//#define VERBOSE
+
+#include "gpio.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+
+#include <openbmc/log.h>
+
+void gpio_init_default(gpio_st *g) {
+ g->gs_gpio = -1;
+ g->gs_fd = -1;
+}
+
+int gpio_open(gpio_st *g, int gpio)
+{
+ char buf[128];
+ int rc;
+
+ snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%u/value", gpio);
+ rc = open(buf, O_RDWR);
+ if (rc == -1) {
+ rc = errno;
+ LOG_ERR(rc, "Failed to open %s", buf);
+ return -rc;
+ }
+ g->gs_fd = rc;
+ g->gs_gpio = gpio;
+ return 0;
+}
+
+void gpio_close(gpio_st *g)
+{
+ if (g && g->gs_fd != -1) {
+ close(g->gs_fd);
+ }
+ gpio_init_default(g);
+}
+
+gpio_value_en gpio_read(gpio_st *g)
+{
+ char buf[32] = {0};
+ gpio_value_en v;
+ lseek(g->gs_fd, 0, SEEK_SET);
+ read(g->gs_fd, buf, sizeof(buf));
+ v = atoi(buf) ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW;
+ LOG_VER("read gpio=%d value=%d %d", g->gs_gpio, atoi(buf), v);
+ return v;
+}
+
+void gpio_write(gpio_st *g, gpio_value_en v)
+{
+ lseek(g->gs_fd, 0, SEEK_SET);
+ write(g->gs_fd, (v == GPIO_VALUE_HIGH) ? "1" : "0", 1);
+ LOG_VER("write gpio=%d value=%d", g->gs_gpio, v);
+}
+
+int gpio_change_direction(gpio_st *g, gpio_direction_en dir)
+{
+ char buf[128];
+ char *val;
+ int fd = -1;
+ int rc = 0;
+
+ snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%u/direction", g->gs_gpio);
+ fd = open(buf, O_WRONLY);
+ if (fd == -1) {
+ rc = errno;
+ LOG_ERR(rc, "Failed to open %s", buf);
+ return -rc;
+ }
+
+ val = (dir == GPIO_DIRECTION_IN) ? "in" : "out";
+ write(fd, val, strlen(val));
+
+ LOG_VER("change gpio=%d direction=%s", g->gs_gpio, val);
+
+ out:
+ if (fd != -1) {
+ close(fd);
+ }
+ return -rc;
+}
diff --git a/common/recipes-lib/gpio/files/src/gpio.h b/common/recipes-lib/gpio/files/src/gpio.h
new file mode 100644
index 0000000..3303986
--- /dev/null
+++ b/common/recipes-lib/gpio/files/src/gpio.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef GPIO_H
+#define GPIO_H
+
+typedef struct {
+ int gs_gpio;
+ int gs_fd;
+} gpio_st;
+
+typedef enum {
+ GPIO_DIRECTION_IN,
+ GPIO_DIRECTION_OUT,
+} gpio_direction_en;
+
+typedef enum {
+ GPIO_VALUE_LOW = 0,
+ GPIO_VALUE_HIGH = 1,
+} gpio_value_en;
+
+int gpio_open(gpio_st* g, int gpio);
+void gpio_close(gpio_st *g);
+gpio_value_en gpio_read(gpio_st *g);
+void gpio_write(gpio_st *g, gpio_value_en v);
+int gpio_change_direction(gpio_st *g, gpio_direction_en dir);
+
+#endif
diff --git a/common/recipes-lib/gpio/libgpio_0.1.bb b/common/recipes-lib/gpio/libgpio_0.1.bb
new file mode 100644
index 0000000..cd32ac0
--- /dev/null
+++ b/common/recipes-lib/gpio/libgpio_0.1.bb
@@ -0,0 +1,40 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "GPIO access library"
+DESCRIPTION = "library to access GPIO"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://gpio.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://src \
+ "
+
+DEPENDS += "liblog"
+
+S = "${WORKDIR}/src"
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 libgpio.so ${D}${libdir}/libgpio.so
+
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 gpio.h ${D}${includedir}/openbmc/gpio.h
+}
+
+FILES_${PN} = "${libdir}/libgpio.so"
+FILES_${PN}-dev = "${includedir}/openbmc/gpio.h"
diff --git a/common/recipes-lib/ipmb/files/Makefile b/common/recipes-lib/ipmb/files/Makefile
new file mode 100644
index 0000000..c09b325
--- /dev/null
+++ b/common/recipes-lib/ipmb/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+lib: libipmb.so
+
+libipmb.so: ipmb.c
+ $(CC) $(CFLAGS) -fPIC -c -o ipmb.o ipmb.c
+ $(CC) -shared -o libipmb.so ipmb.o -lc
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o libipmb.so
diff --git a/common/recipes-lib/ipmb/files/ipmb.c b/common/recipes-lib/ipmb/files/ipmb.c
new file mode 100644
index 0000000..731eeba
--- /dev/null
+++ b/common/recipes-lib/ipmb/files/ipmb.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This file contains code to support IPMI2.0 Specificaton available @
+ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "ipmb.h"
+
+/*
+ * Function to handle IPMB messages
+ */
+void
+lib_ipmb_handle(unsigned char bus_id,
+ unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len) {
+
+ int s, t, len;
+ struct sockaddr_un remote;
+ char sock_path[64] = {0};
+
+ sprintf(sock_path, "%s_%d", SOCK_PATH_IPMB, bus_id);
+
+ // TODO: Need to update to reuse the socket instead of creating new
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ syslog(LOG_ALERT, "lib_ipmb_handle: socket() failed\n");
+ return;
+ }
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, sock_path);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+
+ if (connect(s, (struct sockaddr *)&remote, len) == -1) {
+ syslog(LOG_ALERT, "ipmb_handle: connect() failed\n");
+ goto clean_exit;
+ }
+
+ if (send(s, request, req_len, 0) == -1) {
+ syslog(LOG_ALERT, "ipmb_handle: send() failed\n");
+ goto clean_exit;
+ }
+
+ if ((t=recv(s, response, MAX_IPMB_RES_LEN, 0)) > 0) {
+ *res_len = t;
+ } else {
+ if (t < 0) {
+ syslog(LOG_ALERT, "lib_ipmb_handle: recv() failed\n");
+ } else {
+ printf("Server closed connection\n");
+ }
+ }
+
+clean_exit:
+ close(s);
+
+ return;
+}
diff --git a/common/recipes-lib/ipmb/files/ipmb.h b/common/recipes-lib/ipmb/files/ipmb.h
new file mode 100644
index 0000000..d9bc16b
--- /dev/null
+++ b/common/recipes-lib/ipmb/files/ipmb.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __IPMB_H__
+#define __IPMB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SOCK_PATH_IPMB "/tmp/ipmb_socket"
+
+#define BMC_SLAVE_ADDR 0x10
+#define BRIDGE_SLAVE_ADDR 0x20
+#define ZERO_CKSUM_CONST 0x100
+
+// rqSA, rsSA, rqSeq, hdrCksum, dataCksum
+#define IPMB_HDR_SIZE 5
+
+// rqSA, NetFn, hdrCksum
+#define IPMB_DATA_OFFSET 3
+
+// Slot#0 is on I2C Bus1
+#define IPMB_BUS_SLOT0 1
+
+#define TIMEOUT_IPMI 4
+#define MAX_IPMB_RES_LEN 255
+
+typedef struct _ipmb_req_t {
+ uint8_t res_slave_addr;
+ uint8_t netfn_lun;
+ uint8_t hdr_cksum;
+ uint8_t req_slave_addr;
+ uint8_t seq_lun;
+ uint8_t cmd;
+ uint8_t data[];
+} ipmb_req_t;
+
+typedef struct _ipmb_res_t {
+ uint8_t req_slave_addr;
+ uint8_t netfn_lun;
+ uint8_t hdr_cksum;
+ uint8_t res_slave_addr;
+ uint8_t seq_lun;
+ uint8_t cmd;
+ uint8_t cc;
+ uint8_t data[];
+} ipmb_res_t;
+
+void lib_ipmb_handle(unsigned char bus_id,
+ unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __IPMB_H__ */
diff --git a/common/recipes-lib/ipmb/libipmb_0.1.bb b/common/recipes-lib/ipmb/libipmb_0.1.bb
new file mode 100644
index 0000000..81eed9c
--- /dev/null
+++ b/common/recipes-lib/ipmb/libipmb_0.1.bb
@@ -0,0 +1,26 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "IPMB Client Library"
+DESCRIPTION = "library for IPMB Client"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://ipmb.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec"
+
+
+SRC_URI = "file://Makefile \
+ file://ipmb.c \
+ file://ipmb.h \
+ "
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 libipmb.so ${D}${libdir}/libipmb.so
+
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 ipmb.h ${D}${includedir}/openbmc/ipmb.h
+}
+
+FILES_${PN} = "${libdir}/libipmb.so"
+FILES_${PN}-dev = "${includedir}/openbmc/ipmb.h"
diff --git a/common/recipes-lib/ipmi/files/Makefile b/common/recipes-lib/ipmi/files/Makefile
new file mode 100644
index 0000000..369819c
--- /dev/null
+++ b/common/recipes-lib/ipmi/files/Makefile
@@ -0,0 +1,27 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+lib: libipmi.so
+
+libipmi.so: ipmi.c
+ $(CC) $(CFLAGS) -fPIC -c -o ipmi.o ipmi.c
+ $(CC) -shared -o libipmi.so ipmi.o -lc
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o libipmi.so
diff --git a/common/recipes-lib/ipmi/files/ipmi.c b/common/recipes-lib/ipmi/files/ipmi.c
new file mode 100644
index 0000000..3579eca
--- /dev/null
+++ b/common/recipes-lib/ipmi/files/ipmi.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This file contains code to support IPMI2.0 Specificaton available @
+ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ipmi.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define MAX_IPMI_RES_LEN 100
+
+/*
+ * Function to handle IPMI messages
+ */
+void
+lib_ipmi_handle(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len) {
+
+ int s, t, len;
+ struct sockaddr_un remote;
+
+ // TODO: Need to update to reuse the socket instead of creating new
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ syslog(LOG_ALERT, "lib_ipmi_handle: socket() failed\n");
+ return;
+ }
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, SOCK_PATH_IPMI);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+
+ if (connect(s, (struct sockaddr *)&remote, len) == -1) {
+ syslog(LOG_ALERT, "lib_ipmi_handle: connect() failed\n");
+ return;
+ }
+
+ if (send(s, request, req_len, 0) == -1) {
+ syslog(LOG_ALERT, "lib_ipmi_handle: send() failed\n");
+ return;
+ }
+
+ if ((t=recv(s, response, MAX_IPMI_RES_LEN, 0)) > 0) {
+ *res_len = t;
+ } else {
+ if (t < 0) {
+ syslog(LOG_ALERT, "lib_ipmi_handle: recv() failed\n");
+ } else {
+ printf("Server closed connection");
+ }
+
+ return;
+ }
+
+ close(s);
+
+ return;
+}
diff --git a/common/recipes-lib/ipmi/files/ipmi.h b/common/recipes-lib/ipmi/files/ipmi.h
new file mode 100644
index 0000000..2ae7f1c
--- /dev/null
+++ b/common/recipes-lib/ipmi/files/ipmi.h
@@ -0,0 +1,453 @@
+/*
+ *
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __IPMI_H__
+#define __IPMI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define SOCK_PATH_IPMI "/tmp/ipmi_socket"
+
+#define IPMI_SEL_VERSION 0x51
+#define IPMI_SDR_VERSION 0x51
+
+#define MAX_NUM_DIMMS 4
+
+#define SIZE_AUTH_ENABLES 5
+#define SIZE_IP_ADDR 4
+#define SIZE_MAC_ADDR 6
+#define SIZE_NET_MASK 4
+#define SIZE_IP_HDR 3
+#define SIZE_RMCP_PORT 2
+#define SIZE_COMMUNITY_STR 18
+#define SIZE_DEST_TYPE 4
+#define SIZE_DEST_ADDR 18
+#define SIZE_TIME_STAMP 4
+
+#define SIZE_PROC_FREQ 2
+#define SIZE_DIMM_SPEED 2
+#define SIZE_DIMM_SIZE 2
+
+#define SIZE_SYSFW_VER 17
+#define SIZE_SYS_NAME 17
+#define SIZE_OS_NAME 17
+#define SIZE_OS_VER 17
+#define SIZE_BMC_URL 17
+#define SIZE_OS_HV_URL 17
+
+#define SIZE_SEL_REC 16
+
+#define BIC_INTF_HDR_SIZE 3
+
+#define LUN_OFFSET 2
+
+//NetFn, Cmd
+#define IPMI_REQ_HDR_SIZE 2
+
+// NetFn, Cmd, CC
+#define IPMI_RESP_HDR_SIZE 3
+
+#define MAX_IPMI_MSG_SIZE 100
+
+// Type Definition
+#define TYPE_BINARY 0
+#define TYPE_BCD_PLUS 1
+#define TYPE_ASCII_6BIT 2
+#define TYPE_ASCII_8BIT 3
+
+// IPMI request Structure (IPMI/Section 9.2)
+typedef struct
+{
+ unsigned char netfn_lun;
+ unsigned char cmd;
+ unsigned char data[];
+} ipmi_req_t;
+
+// IPMI Multi Node request Structure
+// Supports additional member to identify the node#
+typedef struct
+{
+ unsigned char payload_id;
+ unsigned char netfn_lun;
+ unsigned char cmd;
+ unsigned char data[];
+} ipmi_mn_req_t;
+
+// IPMI response Structure (IPMI/Section 9.3)
+typedef struct
+{
+ unsigned char netfn_lun;
+ unsigned char cmd;
+ unsigned char cc;
+ unsigned char data[];
+} ipmi_res_t;
+
+// IPMI/Spec Table 20-2
+typedef struct _ipmi_dev_id_t {
+ uint8_t dev_id;
+ uint8_t dev_rev;
+ uint8_t fw_rev1;
+ uint8_t fw_rev2;
+ uint8_t ipmi_ver;
+ uint8_t dev_support;
+ uint8_t mfg_id[3];
+ uint8_t prod_id[2];
+ uint8_t aux_fw_rev[4];
+} ipmi_dev_id_t;
+
+
+typedef struct _ipmi_fruid_info_t {
+ uint8_t size_lsb;
+ uint8_t size_msb;
+ uint8_t bytes_words;
+} ipmi_fruid_info_t;
+
+#pragma pack(push, 1)
+
+// Full Sensor SDR record; IPMI/Section 43.1
+typedef struct {
+ // Sensor Record Header
+ unsigned char rec_id[2];
+ unsigned char ver;
+ unsigned char type;
+ unsigned char len;
+ // Record Key Bytes
+ unsigned char owner;
+ unsigned char lun;
+ unsigned char sensor_num;
+ // Record Body Bytes
+ unsigned char ent_id;
+ unsigned char ent_inst;
+ unsigned char sensor_init;
+ unsigned char sensor_caps;
+ unsigned char sensor_type;
+ unsigned char evt_read_type;
+ union {
+ unsigned char assert_evt_mask[2];
+ unsigned char lt_read_mask[2];
+ };
+ union {
+ unsigned char deassert_evt_mask[2];
+ unsigned char ut_read_mask[2];
+ };
+ union {
+ unsigned char read_evt_mask[2];
+ unsigned char set_thresh_mask[2];
+ };
+ unsigned char sensor_units1;
+ unsigned char sensor_units2;
+ unsigned char sensor_units3;
+ unsigned char linear;
+ unsigned char m_val;
+ unsigned char m_tolerance;
+ unsigned char b_val;
+ unsigned char b_accuracy;
+ unsigned char accuracy_dir;
+ unsigned char rb_exp;
+ unsigned char analog_flags;
+ unsigned char nominal;
+ unsigned char normal_max;
+ unsigned char normal_min;
+ unsigned char max_reading;
+ unsigned char min_reading;
+ unsigned char unr_thresh;
+ unsigned char uc_thresh;
+ unsigned char unc_thresh;
+ unsigned char lnr_thresh;
+ unsigned char lc_thresh;
+ unsigned char lnc_thresh;
+ unsigned char pos_hyst;
+ unsigned char neg_hyst;
+ unsigned char rsvd[2];
+ unsigned char oem;
+ unsigned char str_type_len;
+ char str[16];
+} sdr_full_t;
+
+typedef struct _ipmi_sel_sdr_info_t {
+ uint8_t ver;
+ uint16_t rec_count;
+ uint16_t free_space;
+ uint8_t add_ts[4];
+ uint8_t erase_ts[4];
+ uint8_t oper;
+} ipmi_sel_sdr_info_t;
+
+typedef struct _ipmi_sel_sdr_req_t {
+ uint16_t rsv_id;
+ uint16_t rec_id;
+ uint8_t offset;
+ uint8_t nbytes;
+} ipmi_sel_sdr_req_t;
+
+typedef struct _ipmi_sel_sdr_res_t {
+ uint16_t next_rec_id;
+ uint8_t data[];
+} ipmi_sel_sdr_res_t;
+
+#pragma pack(pop)
+
+// LAN Configuration Structure (IPMI/Table 23.4)
+typedef struct
+{
+ unsigned char set_in_prog;
+ unsigned char auth_support;
+ unsigned char auth_enables[SIZE_AUTH_ENABLES];
+ unsigned char ip_addr[SIZE_IP_ADDR];
+ unsigned char ip_src;
+ unsigned char mac_addr[SIZE_MAC_ADDR];
+ unsigned char net_mask[SIZE_NET_MASK];
+ unsigned char ip_hdr[SIZE_IP_HDR];
+ unsigned char pri_rmcp_port[SIZE_RMCP_PORT];
+ unsigned char sec_rmcp_port[SIZE_RMCP_PORT];
+ unsigned char arp_ctrl;
+ unsigned char garp_interval;
+ unsigned char df_gw_ip_addr[SIZE_IP_ADDR];
+ unsigned char df_gw_mac_addr[SIZE_MAC_ADDR];
+ unsigned char back_gw_ip_addr[SIZE_IP_ADDR];
+ unsigned char back_gw_mac_addr[SIZE_MAC_ADDR];
+ unsigned char community_str[SIZE_COMMUNITY_STR];
+ unsigned char no_of_dest;
+ unsigned char dest_type[SIZE_DEST_TYPE];
+ unsigned char dest_addr[SIZE_DEST_ADDR];
+} lan_config_t;
+
+// Structure to store Processor Information
+typedef struct
+{
+ unsigned char type;
+ unsigned char freq[SIZE_PROC_FREQ];
+} proc_info_t;
+
+// Structure to store DIMM Information
+typedef struct
+{
+ unsigned char type;
+ unsigned char speed[SIZE_DIMM_SPEED];
+ unsigned char size[SIZE_DIMM_SIZE];
+} dimm_info_t;
+
+
+// Structure for System Info Params (IPMI/Section 22.14a)
+typedef struct
+{
+ unsigned char set_in_prog;
+ unsigned char sysfw_ver[SIZE_SYSFW_VER];
+ unsigned char sys_name[SIZE_SYS_NAME];
+ unsigned char pri_os_name[SIZE_OS_NAME];
+ unsigned char present_os_name[SIZE_OS_NAME];
+ unsigned char present_os_ver[SIZE_OS_VER];
+ unsigned char bmc_url[SIZE_BMC_URL];
+ unsigned char os_hv_url[SIZE_OS_HV_URL];
+} sys_info_param_t;
+
+// Structure for Sensor Reading (IPMI/Section 35.14)
+typedef struct
+{
+ uint8_t value;
+ uint8_t flags;
+ uint8_t status;
+ uint8_t ext_status;
+} ipmi_sensor_reading_t;
+
+// Network Function Codes (IPMI/Section 5.1)
+enum
+{
+ NETFN_CHASSIS_REQ = 0x00,
+ NETFN_CHASSIS_RES,
+ NETFN_BRIDGE_REQ,
+ NETFN_BRIDGE_RES,
+ NETFN_SENSOR_REQ,
+ NETFN_SENSOR_RES,
+ NETFN_APP_REQ,
+ NETFN_APP_RES,
+ NETFN_FIRMWARE_REQ,
+ NETFN_FIRMWARE_RES,
+ NETFN_STORAGE_REQ,
+ NETFN_STORAGE_RES,
+ NETFN_TRANSPORT_REQ,
+ NETFN_TRANSPORT_RES,
+ NETFN_OEM_REQ = 0x30,
+ NETFN_OEM_RES = 0x31,
+ NETFN_OEM_1S_REQ = 0x38,
+ NETFN_OEM_1S_RES = 0x39,
+};
+
+// Chassis Command Codes (IPMI/Table H-1)
+enum
+{
+ CMD_CHASSIS_GET_STATUS = 0x01,
+ CMD_CHASSIS_GET_BOOT_OPTIONS = 0x09,
+};
+
+
+// Application Command Codes (IPMI/Table H-1)
+enum
+{
+ CMD_APP_GET_DEVICE_ID = 0x01,
+ CMD_APP_GET_SELFTEST_RESULTS = 0x04,
+ CMD_APP_GET_DEVICE_GUID = 0x08,
+ CMD_APP_RESET_WDT = 0x22,
+ CMD_APP_SET_WDT = 0x24,
+ CMD_APP_GET_WDT = 0x25,
+ CMD_APP_GET_GLOBAL_ENABLES = 0x2F,
+ CMD_APP_GET_SYSTEM_GUID = 0x37,
+ CMD_APP_SET_SYS_INFO_PARAMS = 0x58,
+ CMD_APP_GET_SYS_INFO_PARAMS = 0x59,
+};
+
+// Storage Command Codes (IPMI/Table H-1)
+enum
+{
+ CMD_STORAGE_GET_FRUID_INFO = 0x10,
+ CMD_STORAGE_READ_FRUID_DATA = 0x11,
+ CMD_STORAGE_GET_SDR_INFO = 0x20,
+ CMD_STORAGE_RSV_SDR = 0x22,
+ CMD_STORAGE_GET_SDR = 0x23,
+ CMD_STORAGE_GET_SEL_INFO = 0x40,
+ CMD_STORAGE_RSV_SEL = 0x42,
+ CMD_STORAGE_GET_SEL = 0x43,
+ CMD_STORAGE_ADD_SEL = 0x44,
+ CMD_STORAGE_CLR_SEL = 0x47,
+ CMD_STORAGE_GET_SEL_TIME = 0x48,
+ CMD_STORAGE_GET_SEL_UTC = 0x5C,
+};
+
+// Sensor Command Codes (IPMI/Table H-1)
+enum
+{
+ CMD_SENSOR_GET_SENSOR_READING = 0x2D,
+};
+
+// Transport Command Codes (IPMI/Table H-1)
+enum
+{
+ CMD_TRANSPORT_SET_LAN_CONFIG = 0x01,
+ CMD_TRANSPORT_GET_LAN_CONFIG = 0x02,
+};
+
+// OEM Command Codes (Quanta/FB defined commands)
+enum
+{
+ CMD_OEM_SET_PROC_INFO = 0x1A,
+ CMD_OEM_SET_DIMM_INFO = 0x1C,
+ CMD_OEM_SET_POST_START = 0x73,
+ CMD_OEM_SET_POST_END = 0x74,
+};
+
+// OEM 1S Command Codes (Quanta/FB defined commands)
+enum
+{
+ CMD_OEM_1S_MSG_IN = 0x1,
+ CMD_OEM_1S_GET_GPIO = 0x3,
+ CMD_OEM_1S_GET_GPIO_CONFIG = 0x5,
+ CMD_OEM_1S_SET_GPIO_CONFIG = 0x6,
+ CMD_OEM_1S_INTR = 0x7,
+ CMD_OEM_1S_POST_BUF = 0x8,
+ CMD_OEM_1S_GET_CONFIG = 0xE,
+ CMD_OEM_1S_PLAT_DISC = 0xF,
+ CMD_OEM_1S_SET_CONFIG = 0x10,
+ CMD_OEM_1S_BIC_RESET = 0x11,
+ CMD_OEM_1S_GET_POST_BUF = 0x12,
+ CMD_OEM_1S_BIC_UPDATE_MODE = 0x13,
+};
+
+
+// IPMI command Completion Codes (IPMI/Section 5.2)
+enum
+{
+ CC_SUCCESS = 0x00,
+ CC_INVALID_PARAM = 0x80,
+ CC_SEL_ERASE_PROG = 0x81,
+ CC_INVALID_CMD = 0xC1,
+ CC_PARAM_OUT_OF_RANGE = 0xC9,
+ CC_UNSPECIFIED_ERROR = 0xFF,
+};
+
+// LAN Configuration parameters (IPMI/Table 23-4)
+enum
+{
+ LAN_PARAM_SET_IN_PROG,
+ LAN_PARAM_AUTH_SUPPORT,
+ LAN_PARAM_AUTH_ENABLES,
+ LAN_PARAM_IP_ADDR,
+ LAN_PARAM_IP_SRC,
+ LAN_PARAM_MAC_ADDR,
+ LAN_PARAM_NET_MASK,
+ LAN_PARAM_IP_HDR,
+ LAN_PARAM_PRI_RMCP_PORT,
+ LAN_PARAM_SEC_RMCP_PORT,
+ LAN_PARAM_ARP_CTRL,
+ LAN_PARAM_GARP_INTERVAL,
+ LAN_PARAM_DF_GW_IP_ADDR,
+ LAN_PARAM_DF_GW_MAC_ADDR,
+ LAN_PARAM_BACK_GW_IP_ADDR,
+ LAN_PARAM_BACK_GW_MAC_ADDR,
+ LAN_PARAM_COMMUNITY_STR,
+ LAN_PARAM_NO_OF_DEST,
+ LAN_PARAM_DEST_TYPE,
+ LAN_PARAM_DEST_ADDR,
+};
+
+// Boot Option Parameters (IPMI/Table 28-14)
+enum
+{
+ PARAM_SET_IN_PROG = 0x00,
+ PARAM_SVC_PART_SELECT,
+ PARAM_SVC_PART_SCAN,
+ PARAM_BOOT_FLAG_CLR,
+ PARAM_BOOT_INFO_ACK,
+ PARAM_BOOT_FLAGS,
+ PARAM_BOOT_INIT_INFO,
+};
+
+//System Info Parameters (IPMI/Table 22-16c)
+enum
+{
+ SYS_INFO_PARAM_SET_IN_PROG,
+ SYS_INFO_PARAM_SYSFW_VER,
+ SYS_INFO_PARAM_SYS_NAME,
+ SYS_INFO_PARAM_PRI_OS_NAME,
+ SYS_INFO_PARAM_PRESENT_OS_NAME,
+ SYS_INFO_PARAM_PRESENT_OS_VER,
+ SYS_INFO_PARAM_BMC_URL,
+ SYS_INFO_PARAM_OS_HV_URL,
+};
+
+// Bridge-IC interface on which this command initiated
+enum
+{
+ BIC_INTF_ME = 0x01,
+ BIC_INTF_SOL = 0x02,
+ BIC_INTF_KCS = 0x03,
+};
+
+void lib_ipmi_handle(unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __IPMI_H__ */
diff --git a/common/recipes-lib/ipmi/libipmi_0.2.bb b/common/recipes-lib/ipmi/libipmi_0.2.bb
new file mode 100644
index 0000000..c5bca76
--- /dev/null
+++ b/common/recipes-lib/ipmi/libipmi_0.2.bb
@@ -0,0 +1,41 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "IPMI Client Library"
+DESCRIPTION = "library for IPMI Client"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://ipmi.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec"
+
+
+SRC_URI = "file://Makefile \
+ file://ipmi.c \
+ file://ipmi.h \
+ "
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 libipmi.so ${D}${libdir}/libipmi.so
+
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 ipmi.h ${D}${includedir}/openbmc/ipmi.h
+}
+
+FILES_${PN} = "${libdir}/libipmi.so"
+FILES_${PN}-dev = "${includedir}/openbmc/ipmi.h"
diff --git a/common/recipes-lib/log/files/src/log.h b/common/recipes-lib/log/files/src/log.h
new file mode 100644
index 0000000..a69d69e
--- /dev/null
+++ b/common/recipes-lib/log/files/src/log.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef LOG_H
+#define LOG_H
+
+#include <stdio.h>
+#include <string.h>
+
+//#define DEBUG
+//#define VERBOSE
+
+#define _LOG(dst, fmt, ...) do { \
+ fprintf(dst, "%s:%d " fmt "\n", \
+ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+ fflush(dst); \
+} while(0)
+
+#define LOG_ERR(err, fmt, ...) do { \
+ char buf[128]; \
+ strerror_r(err, buf, sizeof(buf)); \
+ _LOG(stderr, "ERROR " fmt ": %s", ##__VA_ARGS__, buf); \
+} while(0)
+
+#define LOG_INFO(fmt, ...) do { \
+ _LOG(stdout, fmt, ##__VA_ARGS__); \
+} while(0)
+
+#ifdef DEBUG
+#define LOG_DBG(fmt, ...) do { \
+ _LOG(stdout, fmt, ##__VA_ARGS__); \
+} while(0)
+#else
+#define LOG_DBG(fmt, ...)
+#endif
+
+#ifdef VERBOSE
+#define LOG_VER(fmt, ...) do { \
+ _LOG(stdout, fmt, ##__VA_ARGS__); \
+} while(0)
+#else
+#define LOG_VER(fmt, ...)
+#endif
+
+#endif
diff --git a/common/recipes-lib/log/liblog_0.1.bb b/common/recipes-lib/log/liblog_0.1.bb
new file mode 100644
index 0000000..8034c0d
--- /dev/null
+++ b/common/recipes-lib/log/liblog_0.1.bb
@@ -0,0 +1,36 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "Log util functions"
+DESCRIPTION = "some macros to log"
+SECTION = "dev"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://log.h;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI += "file://src \
+ "
+
+S = "${WORKDIR}/src"
+
+do_install() {
+ # common lib and include files
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 log.h ${D}${includedir}/openbmc/log.h
+}
+
+FILES_${PN}-dev = "${includedir}/openbmc/log.h"
diff --git a/common/recipes-lib/sdr/files/Makefile b/common/recipes-lib/sdr/files/Makefile
new file mode 100644
index 0000000..11fe3ee
--- /dev/null
+++ b/common/recipes-lib/sdr/files/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+lib: libsdr.so
+
+libsdr.so: sdr.c
+ $(CC) $(CFLAGS) -fPIC -c -o sdr.o sdr.c
+ $(CC) -lm -shared -o libsdr.so sdr.o -lc
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o libsdr.so
diff --git a/common/recipes-lib/sdr/files/sdr.c b/common/recipes-lib/sdr/files/sdr.c
new file mode 100644
index 0000000..208b10f
--- /dev/null
+++ b/common/recipes-lib/sdr/files/sdr.c
@@ -0,0 +1,210 @@
+/*
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ * This file contains code to support IPMI2.0 Specificaton available @
+ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <syslog.h>
+#include "sdr.h"
+
+#define FIELD_RATE_UNIT(x) ((x & (0x07 << 3)) >> 3)
+#define FIELD_OP(x) ((x & (0x03 << 1)) >> 1)
+#define FIELD_PERCENTAGE(x) (x & 0x01)
+
+#define FIELD_TYPE(x) ((x & (0x03 << 6)) >> 6)
+#define FIELD_LEN(x) (x & 0xF)
+
+/* Array for BCD Plus definition. */
+const char bcd_plus_array[] = "0123456789 -.XXX";
+
+/* Array for 6-Bit ASCII definition. */
+const char * ascii_6bit[4] = {
+ " !\"#$%&'()*+,-./",
+ "0123456789:;<=>?",
+ "@ABCDEFGHIJKLMNO",
+ "PQRSTUVWXYZ[\\]^_"
+};
+
+/* Get the units of the sensor from the SDR */
+int
+sdr_get_sensor_units(sdr_full_t *sdr, uint8_t *op, uint8_t *modifier,
+ char *units) {
+
+ uint8_t percent;
+ uint8_t rate_idx;
+ uint8_t base_idx;
+
+ /* Bits 5:3 */
+ rate_idx = FIELD_RATE_UNIT(sdr->sensor_units1);
+
+ /* Bits 2:1 */
+ *op = FIELD_OP(sdr->sensor_units1);
+
+ /* Bit 0 */
+ percent = FIELD_PERCENTAGE(sdr->sensor_units1);
+
+ base_idx = sdr->sensor_units2;
+
+ if (*op == 0x0 || *op == 0x3)
+ *modifier = 0;
+ else
+ *modifier = sdr->sensor_units3;
+
+ if (percent) {
+ sprintf(units, "%");
+ } else {
+ if (base_idx > 0 && base_idx <= MAX_SENSOR_BASE_UNIT) {
+ if (rate_idx > 0 && rate_idx < MAX_SENSOR_RATE_UNIT) {
+ sprintf(units, "%s %s", sensor_base_units[base_idx],
+ sensor_rate_units[rate_idx]);
+ } else {
+ sprintf(units, "%s", sensor_base_units[base_idx]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Get the name of the sensor from the SDR */
+int
+sdr_get_sensor_name(sdr_full_t *sdr, char *name) {
+ int field_type, field_len;
+ int idx, idx_eff, val;
+ char *str;
+
+ /* Bits 7:6 */
+ field_type = FIELD_TYPE(sdr->str_type_len);
+ /* Bits 4:0 */
+ field_len = FIELD_LEN(sdr->str_type_len) + 1;
+
+ str = sdr->str;
+
+ /* Case: length is zero */
+ if (field_len == 1) {
+ syslog(LOG_ALERT, "get_sensor_name: str length is 0\n");
+ // TODO: Fix this hack later
+ sprintf(name, "%s", str);
+ return -1;
+ }
+
+ /* Retrieve field data depending on the type it was stored. */
+ switch (field_type) {
+ case TYPE_BINARY:
+ /* TODO: Need to add support to read data stored in binary type. */
+ break;
+
+ case TYPE_BCD_PLUS:
+
+ idx = 0;
+ while (idx != field_len) {
+ name[idx] = bcd_plus_array[str[idx] & 0x0F];
+ idx++;
+ }
+ name[idx] = '\0';
+ break;
+
+ case TYPE_ASCII_6BIT:
+
+ idx_eff = idx = 0;
+
+ while (field_len > 0) {
+
+ /* 6-Bits => Bits 5:0 of the first byte */
+ val = str[idx] & 0x3F;
+ name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+ field_len--;
+
+ if (field_len > 0) {
+ /* 6-Bits => Bits 3:0 of second byte + Bits 7:6 of first byte. */
+ val = ((str[idx] & 0xC0) >> 6) |
+ ((str[idx + 1] & 0x0F) << 2);
+ name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+ field_len--;
+ }
+
+ if (field_len > 0) {
+ /* 6-Bits => Bits 1:0 of third byte + Bits 7:4 of second byte. */
+ val = ((str[idx + 1] & 0xF0) >> 4) |
+ ((str[idx + 2] & 0x03) << 4);
+ name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+
+ /* 6-Bits => Bits 7:2 of third byte. */
+ val = ((str[idx + 2] & 0xFC) >> 2);
+ name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F];
+
+ field_len--;
+ idx += 3;
+ }
+ }
+ /* Add Null terminator */
+ name[idx_eff] = '\0';
+ break;
+
+ case TYPE_ASCII_8BIT:
+ snprintf(name, field_len, str);
+ /* Add Null terminator */
+ name[field_len] = '\0';
+ break;
+ }
+
+ return 0;
+}
+
+/* Populates all sensor_info_t struct using the path to SDR dump */
+int
+sdr_init(char *path, sensor_info_t *sinfo) {
+ int fd;
+ uint8_t buf[MAX_SDR_LEN] = {0};
+ uint8_t bytes_rd = 0;
+ uint8_t snr_num = 0;
+ sdr_full_t *sdr;
+
+ while (access(path, F_OK) == -1) {
+ sleep(5);
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ syslog(LOG_ERR, "sdr_init: open failed for %s\n", path);
+ return -1;
+ }
+
+ while ((bytes_rd = read(fd, buf, sizeof(sdr_full_t))) > 0) {
+ if (bytes_rd != sizeof(sdr_full_t)) {
+ syslog(LOG_ERR, "sdr_init: read returns %d bytes\n", bytes_rd);
+ return -1;
+ }
+
+ sdr = (sdr_full_t *) buf;
+ snr_num = sdr->sensor_num;
+ sinfo[snr_num].valid = true;
+ memcpy(&sinfo[snr_num].sdr, sdr, sizeof(sdr_full_t));
+ }
+
+ return 0;
+}
+
diff --git a/common/recipes-lib/sdr/files/sdr.h b/common/recipes-lib/sdr/files/sdr.h
new file mode 100644
index 0000000..c474fb1
--- /dev/null
+++ b/common/recipes-lib/sdr/files/sdr.h
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2015-present Facebook. All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SDR_H__
+#define __SDR_H__
+
+#include <stdbool.h>
+#include <openbmc/ipmi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_SDR_LEN 64
+
+
+#define MAX_SENSOR_RATE_UNIT 7
+#define MAX_SENSOR_BASE_UNIT 92
+
+typedef struct _sensor_info_t {
+ bool valid;
+ sdr_full_t sdr;
+} sensor_info_t;
+
+/* List of all the Sensor Rate Units types. */
+const char * sensor_rate_units[] = {
+ "", /* 0x00 */
+ "per \xC2\xB5s", /* 0x01 */
+ "per ms", /* 0x02 */
+ "per s", /* 0x03 */
+ "per min", /* 0x04 */
+ "per hour", /* 0x05 */
+ "per day", /* 0x06 */
+ "reserved", /* 0x07 */
+};
+
+
+/* List of all the Sensor Base Units types. */
+const char * sensor_base_units[] = {
+ "", /* 000 */
+ "C", /* 001 */
+ "F", /* 002 */
+ "K", /* 003 */
+ "Volts", /* 004 */
+ "Amps", /* 005 */
+ "Watts", /* 006 */
+ "Joules", /* 007 */
+ "Coulombs", /* 008 */
+ "VA", /* 009 */
+ "Nits", /* 010 */
+ "lumen", /* 011 */
+ "lux", /* 012 */
+ "Candela", /* 013 */
+ "kPa", /* 014 */
+ "PSI", /* 015 */
+ "Newton", /* 016 */
+ "CFM", /* 017 */
+ "RPM", /* 018 */
+ "Hz", /* 019 */
+ "\xC2\xB5s", /* 020 */
+ "ms", /* 021 */
+ "sec", /* 022 */
+ "min", /* 023 */
+ "hour", /* 024 */
+ "day", /* 025 */
+ "week", /* 026 */
+ "mil", /* 027 */
+ "inches", /* 028 */
+ "feet", /* 029 */
+ "cu in", /* 030 */
+ "cu feet", /* 031 */
+ "mm", /* 032 */
+ "cm", /* 033 */
+ "m", /* 034 */
+ "cu cm", /* 035 */
+ "cu m", /* 036 */
+ "liters", /* 037 */
+ "fluid ounce", /* 038 */
+ "radians", /* 039 */
+ "steradians", /* 040 */
+ "revolutions", /* 041 */
+ "cycles", /* 042 */
+ "gravities", /* 043 */
+ "ounce", /* 044 */
+ "pound", /* 045 */
+ "ft-lb", /* 046 */
+ "oz-in", /* 047 */
+ "gauss", /* 048 */
+ "gilberts", /* 049 */
+ "henry", /* 050 */
+ "millihenry", /* 051 */
+ "farad", /* 052 */
+ "microfarad", /* 053 */
+ "ohms", /* 054 */
+ "siemens", /* 055 */
+ "mole", /* 056 */
+ "becquerel", /* 057 */
+ "PPM", /* 058 */
+ "reserved", /* 059 */
+ "Db", /* 060 */
+ "DbA", /* 061 */
+ "DbC", /* 062 */
+ "gray", /* 063 */
+ "sievert", /* 064 */
+ "color temp deg K", /* 065 */
+ "bit", /* 066 */
+ "kilobit", /* 067 */
+ "megabit", /* 068 */
+ "gigabit", /* 069 */
+ "B", /* 070 */
+ "KB", /* 071 */
+ "MB", /* 072 */
+ "GB", /* 073 */
+ "word", /* 074 */
+ "dword", /* 075 */
+ "qword", /* 076 */
+ "line", /* 077 */
+ "hit", /* 078 */
+ "miss", /* 079 */
+ "retry", /* 080 */
+ "reset", /* 081 */
+ "overflow", /* 082 */
+ "underrun", /* 083 */
+ "collision", /* 084 */
+ "packets", /* 085 */
+ "messages", /* 086 */
+ "characters", /* 087 */
+ "error", /* 088 */
+ "correctable error", /* 089 */
+ "uncorrectable error", /* 090 */
+ "fatal error", /* 091 */
+ "grams", /* 092 */
+ "", /* 093 */
+};
+
+int sdr_init(char *path, sensor_info_t *sinfo);
+
+int sdr_get_sensor_units(sdr_full_t *sdr, uint8_t *op, uint8_t *modifier,
+ char *units);
+int sdr_get_sensor_name(sdr_full_t *sdr, char *name);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __SDR_H__ */
diff --git a/common/recipes-lib/sdr/libsdr_0.1.bb b/common/recipes-lib/sdr/libsdr_0.1.bb
new file mode 100644
index 0000000..958e0c6
--- /dev/null
+++ b/common/recipes-lib/sdr/libsdr_0.1.bb
@@ -0,0 +1,30 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+SUMMARY = "SDR Library"
+DESCRIPTION = "library for extracting information from SDR"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+
+
+LIC_FILES_CHKSUM = "file://sdr.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec"
+
+
+SRC_URI = "file://Makefile \
+ file://sdr.c \
+ file://sdr.h \
+ "
+
+S = "${WORKDIR}"
+
+DEPENDS += " libipmi "
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 libsdr.so ${D}${libdir}/libsdr.so
+
+ install -d ${D}${includedir}/openbmc
+ install -m 0644 sdr.h ${D}${includedir}/openbmc/sdr.h
+}
+
+FILES_${PN} = "${libdir}/libsdr.so"
+FILES_${PN}-dev = "${includedir}/openbmc/sdr.h"
diff --git a/common/recipes-rest/rest-api/files/node.py b/common/recipes-rest/rest-api/files/node.py
new file mode 100644
index 0000000..41e0a3e
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+# Class Definition for Resource
+
+class node:
+ def __init__(self, info = None, actions = None):
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ return self.info
+
+ def getActions(self):
+ return self.actions
+
+ def doAction(self, action):
+ result = { "result": 'failure', "reason": 'not supported'}
diff --git a/common/recipes-rest/rest-api/files/node_api.py b/common/recipes-rest/rest-api/files/node_api.py
new file mode 100644
index 0000000..ca5cc5c
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_api.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+from node import node
+from pal import *
+
+def get_node_api():
+
+ name = pal_get_platform_name()
+ info = {
+ "Description": name + " RESTful API Entry",
+ }
+
+ return node(info)
diff --git a/common/recipes-rest/rest-api/files/node_bmc.py b/common/recipes-rest/rest-api/files/node_bmc.py
new file mode 100644
index 0000000..14b51e7
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_bmc.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+
+from subprocess import *
+import re
+from node import node
+from pal import *
+
+class bmcNode(node):
+ def __init__(self, info = None, actions = None):
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ # Get Platform Name
+ name = pal_get_platform_name()
+
+ # Get BMC Reset Reason
+ wdt_counter = Popen('devmem 0x1e785010', \
+ shell=True, stdout=PIPE).stdout.read()
+ wdt_counter = int(wdt_counter, 0)
+
+ wdt_counter &= 0xff00
+
+ if wdt_counter:
+ por_flag = 0
+ else:
+ por_flag = 1
+
+ if por_flag:
+ reset_reason = "Power ON Reset"
+ else:
+ reset_reason = "User Initiated Reset or WDT Reset"
+
+ # Get BMC's Up Time
+ uptime = Popen('uptime', \
+ shell=True, stdout=PIPE).stdout.read()
+
+ # Get Usage information
+ data = Popen('top -b n1', \
+ shell=True, stdout=PIPE).stdout.read()
+ adata = data.split('\n')
+ mem_usage = adata[0]
+ cpu_usage = adata[1]
+
+ # Get OpenBMC version
+ version = ""
+ data = Popen('cat /etc/issue', \
+ shell=True, stdout=PIPE).stdout.read()
+ #Version might start with 'v'(wedge) or 'V'(Yosemite)
+ if name == 'Yosemite':
+ ver = re.search(r'V([\w\d._-]*)\s', data)
+ else:
+ ver = re.search(r'v([\w\d._-]*)\s', data)
+ if ver:
+ version = ver.group(1)
+
+
+ info = {
+ "Description": name + " BMC",
+ "Reset Reason": reset_reason,
+ "Uptime": uptime,
+ "Memory Usage": mem_usage,
+ "CPU Usage": cpu_usage,
+ "OpenBMC Version": version,
+ }
+
+ return info;
+
+def get_node_bmc():
+ return bmcNode()
diff --git a/common/recipes-rest/rest-api/files/node_config.py b/common/recipes-rest/rest-api/files/node_config.py
new file mode 100644
index 0000000..d37cc25
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_config.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+
+import os
+from subprocess import *
+from node import node
+from pal import *
+
+class configNode(node):
+ def __init__(self, name = None, actions = None):
+ self.name = name
+
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ result = {}
+ cmd = '/usr/local/bin/cfg-util dump-all'
+ data = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
+ sdata = data.split('\n');
+ for line in sdata:
+ # skip lines that does not start with name
+ if line.startswith(self.name):
+ kv = line.split(':')
+ result[kv[0].strip()] = kv[1].strip()
+ return result
+
+ def doAction(self, data):
+ res = "success"
+ # Get the list of parameters to be updated
+ params = data["update"]
+ for key in params.keys():
+ # update only if the key starts with the name
+ if key.startswith(self.name):
+ ret = pal_set_key_value(key, params[key])
+ if ret:
+ res = "failure"
+
+ result = {"result": res}
+
+ return result
+
+def get_node_config(name):
+ actions = ["update"]
+ return configNode(name = name, actions = actions)
diff --git a/common/recipes-rest/rest-api/files/node_fruid.py b/common/recipes-rest/rest-api/files/node_fruid.py
new file mode 100644
index 0000000..d7a1dc3
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_fruid.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+from subprocess import *
+from node import node
+
+class fruidNode(node):
+ def __init__(self, name, info = None, actions = None):
+ self.name = name
+
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ result = {}
+ cmd = '/usr/local/bin/fruid-util ' + self.name
+ data = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
+ sdata = data.split('\n')
+ for line in sdata:
+ # skip lines with --- or startin with FRU
+ if line.find("FRU") != -1:
+ continue
+ if line.find("-----") != -1:
+ continue
+
+ kv = line.split(':')
+ if (len(kv) < 2):
+ continue
+
+ result[kv[0].strip()] = kv[1].strip()
+
+ return result
+
+def get_node_fruid(name):
+ return fruidNode(name)
diff --git a/common/recipes-rest/rest-api/files/node_sensors.py b/common/recipes-rest/rest-api/files/node_sensors.py
new file mode 100644
index 0000000..0e7ffc1
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_sensors.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+from subprocess import *
+import json
+import os
+import re
+from node import node
+
+class sensorsNode(node):
+ def __init__(self, name, info = None, actions = None):
+ self.name = name
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ result = {}
+ cmd = '/usr/local/bin/sensor-util ' + self.name
+ data = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
+ sdata = data.split('\n')
+ for line in sdata:
+ # skip lines with " or startin with FRU
+ if line.find("bic_read_sensor_wrapper") != -1:
+ continue
+ if line.find("failed") != -1:
+ continue
+
+ kv = line.split(':')
+ if (len(kv) < 2):
+ continue
+
+ result[kv[0].strip()] = kv[1].strip()
+
+ return result
+
+def get_node_sensors(name):
+ return sensorsNode(name)
diff --git a/common/recipes-rest/rest-api/files/node_server.py b/common/recipes-rest/rest-api/files/node_server.py
new file mode 100644
index 0000000..57a5c42
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_server.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+
+import os
+from subprocess import *
+from node import node
+from pal import *
+
+class serverNode(node):
+ def __init__(self, num = None, info = None, actions = None):
+ self.num = num
+
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def getInformation(self):
+ ret = pal_get_server_power(self.num)
+ if ret == 0:
+ status = 'power-off'
+ elif ret == 1:
+ status = 'power-on'
+ else:
+ status = 'error'
+
+ info = { "status": status }
+
+ return info
+
+ def doAction(self, data):
+ if pal_set_server_power(self.num, data["action"]) == -1:
+ res = 'failure'
+ else:
+ res = 'success'
+
+ result = { "result": res }
+
+ return result
+
+def get_node_server(num):
+ actions = ["power-on",
+ "power-off",
+ "power-cycle",
+ "graceful-shutdown"
+ ]
+ return serverNode(num = num, actions = actions)
diff --git a/common/recipes-rest/rest-api/files/node_spb.py b/common/recipes-rest/rest-api/files/node_spb.py
new file mode 100644
index 0000000..a9fe4e6
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/node_spb.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+from node import node
+from pal import *
+
+class spbNode(node):
+ def __init__(self, info = None, actions = None):
+ if info == None:
+ self.info = {}
+ else:
+ self.info = info
+
+ if actions == None:
+ self.actions = []
+ else:
+ self.actions = actions
+
+ def doAction(self, data):
+ if pal_sled_cycle(data["action"]) == -1:
+ res = 'failure'
+ else:
+ res = 'success'
+
+ result = { "result": res }
+
+ return result
+
+def get_node_spb():
+ name = pal_get_platform_name()
+ info = {
+ "Description": name + " Side Plane",
+ }
+
+ actions = [ "sled-cycle" ]
+ return spbNode(info, actions)
diff --git a/common/recipes-rest/rest-api/files/pal.py b/common/recipes-rest/rest-api/files/pal.py
new file mode 100644
index 0000000..8faef30
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/pal.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+from ctypes import *
+
+lpal_hndl = CDLL("libpal.so")
+
+def pal_get_platform_name():
+ name = create_string_buffer(16)
+ ret = lpal_hndl.pal_get_platform_name(name)
+ if ret:
+ return None
+ else:
+ return name.value
+
+def pal_get_num_slots():
+ num = c_ubyte()
+ p_num = pointer(num)
+ ret = lpal_hndl.pal_get_num_slots(p_num)
+ if ret:
+ return None
+ else:
+ return num.value
+
+def pal_is_server_prsnt(slot_id):
+ status = c_ubyte()
+ p_status = pointer(status)
+ ret = lpal_hndl.pal_is_server_prsnt(slot_id, p_status)
+ if ret:
+ return None
+ else:
+ return status.value
+
+def pal_get_server_power(slot_id):
+ status = c_ubyte()
+ p_status = pointer(status)
+ ret = lpal_hndl.pal_get_server_power(slot_id, p_status)
+ if ret:
+ return None
+ else:
+ return status.value
+
+def pal_set_server_power(slot_id, command):
+ cmd = c_ubyte()
+ if command == 'power-off':
+ cmd.value = 0
+ elif command == 'power-on':
+ cmd.value = 1
+ elif command == 'power-cycle':
+ cmd.value = 2
+ elif command == 'graceful-shutdown':
+ cmd.value = 3
+ ret = lpal_hndl.pal_set_server_power(slot_id, cmd)
+ if ret:
+ return -1
+ else:
+ return 0
+
+def pal_sled_cycle(command):
+ if command != 'sled-cycle':
+ return -1
+
+ ret = lpal_hndl.pal_sled_cycle()
+ if ret:
+ return -1
+ else:
+ return 0
+
+def pal_set_key_value(key, value):
+ pkey = create_string_buffer(key)
+ pvalue = create_string_buffer(value)
+
+ ret = lpal_hndl.pal_set_key_value(pkey, pvalue)
+ if ret:
+ return -1;
+ else:
+ return 0;
diff --git a/common/recipes-rest/rest-api/files/rest.py b/common/recipes-rest/rest-api/files/rest.py
new file mode 100644
index 0000000..0a90d54
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/rest.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+from ctypes import *
+from bottle import route, run, template, request, response, ServerAdapter
+from bottle import abort
+from wsgiref.simple_server import make_server, WSGIRequestHandler, WSGIServer
+import json
+import ssl
+import socket
+import os
+from tree import tree
+from node import node
+from plat_tree import init_plat_tree
+
+CONSTANTS = {
+ 'certificate': '/usr/lib/ssl/certs/rest_server.pem',
+}
+
+root = init_plat_tree()
+
+# Generic router for incoming requests
+@route('/<path:path>', method='ANY')
+def url_router(path):
+ token = path.split('/')
+ # Find the Node
+ r = root
+ for t in token:
+ r = r.getChildByName(t)
+ if r == None:
+ return r
+ c = r.data
+
+ # Handle GET request
+ if request.method == 'GET':
+ # Gather info/actions directly from respective node
+ info = c.getInformation()
+ actions = c.getActions()
+
+ # Create list of resources from tree structure
+ resources = []
+ ca = r.getChildren()
+ for t in ca:
+ resources.append(t.name)
+ result = {'Information': info,
+ 'Actions': actions,
+ 'Resources': resources }
+
+ return result
+
+ # Handle POST request
+ if request.method == 'POST':
+ return c.doAction(json.load(request.body))
+
+ return None
+
+run(host = "::", port = 8080)
+
+# TODO: Test the https connection with proper certificates
+# SSL Wrapper for Rest API
+class SSLWSGIRefServer(ServerAdapter):
+ def run(self, handler):
+ if self.quiet:
+ class QuietHandler(WSGIRequestHandler):
+ def log_request(*args, **kw): pass
+ self.options['handler_class'] = QuietHandler
+
+ # IPv6 Support
+ server_cls = self.options.get('server_class', WSGIServer)
+
+ if ':' in self.host:
+ if getattr(server_cls, 'address_family') == socket.AF_INET:
+ class server_cls(server_cls):
+ address_family = socket.AF_INET6
+
+ srv = make_server(self.host, self.port, handler,
+ server_class=server_cls, **self.options)
+ srv.socket = ssl.wrap_socket (
+ srv.socket,
+ certfile=CONSTANTS['certificate'],
+ server_side=True)
+ srv.serve_forever()
+
+# Use SSL if the certificate exists. Otherwise, run without SSL.
+if os.access(CONSTANTS['certificate'], os.R_OK):
+ run(server=SSLWSGIRefServer(host="::", port=8443))
+else:
+ run(host = "::", port = 8080)
diff --git a/common/recipes-rest/rest-api/files/tree.py b/common/recipes-rest/rest-api/files/tree.py
new file mode 100644
index 0000000..ca81510
--- /dev/null
+++ b/common/recipes-rest/rest-api/files/tree.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+# Class Definition for Tree
+
+class tree:
+ def __init__(self, name, data = None):
+ self.name = name
+ self.data = data
+ self.children = []
+
+ def addChild(self, child):
+ self.children.append(child)
+
+ def addChildren(self, children):
+ for child in children:
+ self.children.append(child)
+
+ def getChildren(self):
+ return self.children
+
+ def getChildByName(self, name):
+ if self.name == name:
+ return self
+
+ for child in self.children:
+ if child.name == name:
+ return child
+ return None
diff --git a/common/recipes-rest/rest-api/rest-api_0.2.bb b/common/recipes-rest/rest-api/rest-api_0.2.bb
new file mode 100644
index 0000000..1956cb2
--- /dev/null
+++ b/common/recipes-rest/rest-api/rest-api_0.2.bb
@@ -0,0 +1,36 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "Rest API Daemon"
+DESCRIPTION = "Daemon to handle RESTful interface."
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://rest.py;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0"
+
+
+SRC_URI = "file://rest.py \
+ file://node.py \
+ file://tree.py \
+ file://pal.py \
+ "
+DEPENDS += "libpal"
+
+
+binfiles = "rest.py node.py tree.py pal.py"
+
+pkgdir = "rest-api"
+RDEPENDS_${PN} += "libpal"
diff --git a/common/recipes-utils/bitbang/bitbang_0.1.bb b/common/recipes-utils/bitbang/bitbang_0.1.bb
new file mode 100644
index 0000000..16fdbd3
--- /dev/null
+++ b/common/recipes-utils/bitbang/bitbang_0.1.bb
@@ -0,0 +1,37 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "Device driver using GPIO bitbang"
+DESCRIPTION = "Various device driver using GPIO bitbang"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://bitbang.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://src \
+ "
+
+DEPENDS += "openbmc-utils libgpio"
+
+S = "${WORKDIR}/src"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 755 spi-bb ${D}${bindir}/spi-bb
+ install -m 755 mdio-bb ${D}${bindir}/mdio-bb
+}
+
+FILES_${PN} = "${bindir}"
diff --git a/common/recipes-utils/bitbang/files/src/Makefile b/common/recipes-utils/bitbang/files/src/Makefile
new file mode 100644
index 0000000..24e4220
--- /dev/null
+++ b/common/recipes-utils/bitbang/files/src/Makefile
@@ -0,0 +1,29 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+all: spi-bb mdio-bb
+
+spi-bb: spi_bb.o bitbang.o
+ $(CC) -o $@ $^ $(LDFLAGS) -lgpio
+
+mdio-bb: mdio_bb.o bitbang.o
+ $(CC) -o $@ $^ $(LDFLAGS) -lgpio
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o spi-bb mdio-bb
diff --git a/common/recipes-utils/bitbang/files/src/bitbang.c b/common/recipes-utils/bitbang/files/src/bitbang.c
new file mode 100644
index 0000000..1318f42
--- /dev/null
+++ b/common/recipes-utils/bitbang/files/src/bitbang.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+//#define DEBUG
+//#define VERBOSE
+
+#include "bitbang.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <openbmc/log.h>
+
+#define NANOSEC_IN_SEC (1000 * 1000 * 1000)
+
+#define BITBANG_FREQ_MAX (500 * 1000 * 1000) /* 500M Hz */
+#define BITBANG_FREQ_DEFAULT (1 * 1000 * 1000) /* 1M Hz */
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+struct bitbang_handle {
+ bitbang_init_st bbh_init;
+ uint32_t bbh_half_clk; /* ns per clock cycle */
+};
+
+void bitbang_init_default(bitbang_init_st *init)
+{
+ memset(init, sizeof(*init), 0);
+ init->bbi_clk_start = BITBANG_PIN_HIGH;
+ init->bbi_data_out = BITBANG_CLK_EDGE_FALLING;
+ init->bbi_data_in = BITBANG_CLK_EDGE_RISING;
+ init->bbi_freq = BITBANG_FREQ_DEFAULT;
+}
+
+bitbang_handle_st* bitbang_open(const bitbang_init_st *init)
+{
+ bitbang_handle_st *hdl;
+
+ if (!init || !init->bbi_pin_f
+ || !init->bbi_freq || init->bbi_freq > BITBANG_FREQ_MAX) {
+ LOG_ERR(EINVAL, "Invalid init structure");
+ return NULL;
+ }
+
+ hdl = calloc(1, sizeof(*hdl));
+ if (!hdl) {
+ return NULL;
+ }
+
+ hdl->bbh_init = *init;
+ hdl->bbh_half_clk = NANOSEC_IN_SEC / init->bbi_freq / 2;
+
+ LOG_DBG("Bitbang open with initial %s, data out at %s, data in at %s, "
+ "freq at %uHz, half clk %uns",
+ (init->bbi_clk_start == BITBANG_PIN_LOW) ? "LOW" : "HIGH",
+ (init->bbi_data_out == BITBANG_CLK_EDGE_RISING)
+ ? "RISING" : "FALLING",
+ (init->bbi_data_in == BITBANG_CLK_EDGE_RISING)
+ ? "RISING" : "FALLING",
+ init->bbi_freq, hdl->bbh_half_clk);
+
+ return hdl;
+}
+
+void bitbang_close(bitbang_handle_st *hdl)
+{
+ free(hdl);
+}
+
+/*
+ * The threshold (ns) to use spin instead of nanosleep().
+ * Before adding the high resolution timer support, either spin or nanosleep()
+ * will not bring the process wakeup within 10ms. It turns out the system time
+ * update is also controlled by HZ (100).
+ * After I added the high resolution timer support, the spin works as the
+ * system time is updated more frequently. However, nanosleep() solution is
+ * still noticable slower comparing with spin. There could be some kernel
+ * scheduling tweak missing. Did not get time on that yet.
+ * For now, use 10ms as the threshold to determine if spin or nanosleep()
+ * is used.
+ */
+#define BITBANG_SPIN_THRESHOLD (10 * 1000 * 1000)
+
+static int sleep_ns(uint32_t clk)
+{
+ struct timespec req, rem;
+ int rc = 0;
+ if (clk <= BITBANG_SPIN_THRESHOLD) {
+ struct timespec orig;
+ rc = clock_gettime(CLOCK_MONOTONIC, &req);
+ orig = req;
+ while (!rc && clk) {
+ uint32_t tmp;
+ rc = clock_gettime(CLOCK_MONOTONIC, &rem);
+ tmp = (rem.tv_sec - req.tv_sec) * NANOSEC_IN_SEC;
+ if (rem.tv_nsec >= req.tv_nsec) {
+ tmp += rem.tv_nsec - req.tv_nsec;
+ } else {
+ tmp -= req.tv_nsec - rem.tv_nsec;
+ }
+ if (tmp >= clk) {
+ break;
+ }
+ clk -= tmp;
+ req = rem;
+ }
+ } else {
+ req.tv_sec = 0;
+ req.tv_nsec = clk;
+ while ((rc = nanosleep(&req, &rem)) == -1 && errno == EINTR) {
+ req = rem;
+ }
+ }
+ if (rc == -1) {
+ rc = errno;
+ LOG_ERR(rc, "Failed to sleep %u nanoseconds", clk);
+ }
+ return rc;
+}
+
+int bitbang_io(const bitbang_handle_st *hdl, bitbang_io_st *io)
+{
+ int rc = 0;
+ uint32_t clk = hdl->bbh_half_clk;
+ const struct {
+ bitbang_pin_value_en value;
+ bitbang_clk_edge_en edge;
+ } clks[] = {
+ {BITBANG_PIN_HIGH, BITBANG_CLK_EDGE_FALLING},
+ {BITBANG_PIN_LOW, BITBANG_CLK_EDGE_RISING},
+ };
+ int clk_idx;
+ int n_clk = 0;
+ int n_bits = 0;
+ const uint8_t *dout = io->bbio_dout;
+ uint8_t *din = io->bbio_din;
+ int bit_pos = 7;
+ bitbang_pin_func pin_f = hdl->bbh_init.bbi_pin_f;
+ void *context = hdl->bbh_init.bbi_context;
+
+ if ((io->bbio_in_bits == 0 && io->bbio_din)
+ || (io->bbio_in_bits > 0 && !io->bbio_din)) {
+ rc = EINVAL;
+ LOG_ERR(rc, "Incorrect in bits and in buffer");
+ goto out;
+ }
+
+ if ((io->bbio_out_bits == 0 && io->bbio_dout)
+ || (io->bbio_out_bits > 0 && !io->bbio_dout)) {
+ rc = EINVAL;
+ LOG_ERR(rc, "Incorrect out bits and out buffer");
+ goto out;
+ }
+
+ if (io->bbio_in_bits == 0 && io->bbio_out_bits == 0) {
+ rc = EINVAL;
+ LOG_ERR(rc, "Both in and out bits are 0");
+ goto out;
+ }
+
+ if (hdl->bbh_init.bbi_clk_start == BITBANG_PIN_HIGH) {
+ clk_idx = 0;
+ } else {
+ clk_idx = 1;
+ }
+
+ /* set the CLK pin start position */
+ pin_f(BITBANG_CLK_PIN, clks[clk_idx].value, context);
+
+ /* clear the first byte of din */
+ if (din && io->bbio_in_bits) {
+ memset(din, 0, (io->bbio_in_bits + 7) / 8);
+ }
+
+ do {
+ if ((rc = sleep_ns(clk))) {
+ goto out;
+ }
+
+ /* output first */
+ if (hdl->bbh_init.bbi_data_out == clks[clk_idx].edge) {
+ if (dout && n_bits < io->bbio_out_bits) {
+ pin_f(BITBANG_DATA_OUT, (*dout >> bit_pos) & 0x1, context);
+ }
+ }
+
+ /* then, input */
+ if (hdl->bbh_init.bbi_data_in == clks[clk_idx].edge) {
+ if (din && n_bits < io->bbio_in_bits) {
+ *din |= (pin_f(BITBANG_DATA_IN, 0, context) & 0x1) << bit_pos;
+ }
+ }
+
+ if (++n_clk % 2 == 0) {
+ /* one bit for every 2 half clks */
+ n_bits ++;
+ if (bit_pos == 0) {
+ if (dout) {
+ dout++;
+ }
+ if (din) {
+ din++;
+ }
+ bit_pos = 7;
+ } else {
+ bit_pos --;
+ }
+ }
+ clk_idx = 1 - clk_idx;
+ pin_f(BITBANG_CLK_PIN, clks[clk_idx].value, context);
+ } while (n_bits < MAX(io->bbio_in_bits, io->bbio_out_bits));
+
+ out:
+
+ return -rc;
+}
diff --git a/common/recipes-utils/bitbang/files/src/bitbang.h b/common/recipes-utils/bitbang/files/src/bitbang.h
new file mode 100644
index 0000000..0f21a49
--- /dev/null
+++ b/common/recipes-utils/bitbang/files/src/bitbang.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef BITBANG_H
+#define BITBANG_H
+
+#include <stdint.h>
+
+typedef enum {
+ BITBANG_CLK_PIN,
+ BITBANG_DATA_IN,
+ BITBANG_DATA_OUT,
+} bitbang_pin_type_en;
+
+typedef enum {
+ BITBANG_PIN_LOW = 0,
+ BITBANG_PIN_HIGH = 1,
+} bitbang_pin_value_en;
+
+typedef enum {
+ BITBANG_CLK_EDGE_RISING,
+ BITBANG_CLK_EDGE_FALLING,
+} bitbang_clk_edge_en;
+
+typedef bitbang_pin_value_en (* bitbang_pin_func)(
+ bitbang_pin_type_en pin, bitbang_pin_value_en value, void *context);
+
+typedef struct {
+ bitbang_pin_value_en bbi_clk_start;
+ bitbang_clk_edge_en bbi_data_out;
+ bitbang_clk_edge_en bbi_data_in;
+ uint32_t bbi_freq;
+ bitbang_pin_func bbi_pin_f;
+ void *bbi_context;
+} bitbang_init_st;
+
+typedef struct bitbang_handle bitbang_handle_st;
+
+void bitbang_init_default(bitbang_init_st *init);
+bitbang_handle_st* bitbang_open(const bitbang_init_st *init);
+void bitbang_close(bitbang_handle_st *hdl);
+
+typedef struct {
+ uint32_t bbio_in_bits;
+ uint32_t bbio_out_bits;
+ uint8_t *bbio_dout;
+ uint8_t *bbio_din;
+} bitbang_io_st;
+
+int bitbang_io(const bitbang_handle_st *hdl, bitbang_io_st *io);
+
+#endif
diff --git a/common/recipes-utils/bitbang/files/src/mdio_bb.c b/common/recipes-utils/bitbang/files/src/mdio_bb.c
new file mode 100644
index 0000000..9137e17
--- /dev/null
+++ b/common/recipes-utils/bitbang/files/src/mdio_bb.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+//#define DEBUG
+//#define VERBOSE
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <openbmc/log.h>
+#include <openbmc/gpio.h>
+
+#include "bitbang.h"
+
+typedef struct {
+ gpio_st m_mdc;
+ gpio_st m_mdio;
+} mdio_context_st;
+
+/*
+ * 32b preamble, 2b start of frame, 2b operation code,
+ * 5b phy addr, 5b register addr, 2b turnaround, 16b data
+ */
+#define N_BITS (32 + 2 + 2 + 5 + 5 + 2 + 16)
+#define N_BYTES (N_BITS + 7 / 8)
+
+#define START_OF_FRAME 0x1
+#define OP_READ 0x2
+#define OP_WRITE 0x1
+#define TURNAROUND 0x2 /* TA for write, for read, phy sends out TA */
+
+void usage()
+{
+ fprintf(stderr,
+ "Usage:\n"
+ "mdio-bb: -c <GPIO for MDC> [-C <HIGH|low>]\n"
+ " -d <GPIO for MDIO> [-O <rising|FALLING>]\n"
+ " [-I <RISING|falling>] [-p] [-b]\n"
+ " <read|write> <phy address> <register address>\n"
+ " [value to write]\n");
+}
+
+bitbang_pin_value_en mdio_pin_f(
+ bitbang_pin_type_en pin, bitbang_pin_value_en value, void *context)
+{
+ mdio_context_st *ctx = (mdio_context_st *)context;
+ gpio_st *gpio;
+ bitbang_pin_value_en res;
+
+ switch (pin) {
+ case BITBANG_CLK_PIN:
+ gpio = &ctx->m_mdc;
+ break;
+ case BITBANG_DATA_IN:
+ case BITBANG_DATA_OUT:
+ gpio = &ctx->m_mdio;
+ break;
+ }
+ if (pin == BITBANG_DATA_IN) {
+ res = gpio_read(gpio) ? BITBANG_PIN_HIGH : BITBANG_PIN_LOW;
+ } else {
+ res = value;
+ gpio_write(gpio, ((res == BITBANG_PIN_HIGH)
+ ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW));
+ }
+ return res;
+}
+
+int main(int argc, char* const argv[])
+{
+ int opt;
+ int mdc = -1, mdio = -1;
+ bitbang_pin_value_en mdc_start = BITBANG_PIN_HIGH;
+ bitbang_clk_edge_en out_edge = BITBANG_CLK_EDGE_FALLING;
+ bitbang_clk_edge_en in_edge = BITBANG_CLK_EDGE_RISING;
+ int is_write;
+ uint32_t phy_addr;
+ uint32_t reg_addr;
+ uint32_t data; /* data to write/read*/
+ uint8_t buf[N_BYTES];
+ uint8_t *buf_p;
+ mdio_context_st ctx;
+ bitbang_init_st init;
+ bitbang_handle_st *hdl = NULL;
+ bitbang_io_st io;
+ int n_bits;
+ int i;
+ int rc = 0;
+ int preamble = 0;
+ int binary = 0;
+
+ while ((opt = getopt(argc, argv, "bc:C:d:D:p")) != -1) {
+ switch (opt) {
+ case 'b':
+ binary = 1;
+ break;
+ case 'c':
+ mdc = atoi(optarg);
+ break;
+ case 'C':
+ if (!strcasecmp(optarg, "high")) {
+ mdc_start = BITBANG_PIN_HIGH;
+ } else if (!strcasecmp(optarg, "low")) {
+ mdc_start = BITBANG_PIN_LOW;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'd':
+ mdio = atoi(optarg);
+ break;
+ case 'I':
+ if (!strcasecmp(optarg, "rising")) {
+ in_edge = BITBANG_CLK_EDGE_RISING;
+ } if (!strcasecmp(optarg, "falling")) {
+ in_edge = BITBANG_CLK_EDGE_FALLING;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'O':
+ if (!strcasecmp(optarg, "rising")) {
+ out_edge = BITBANG_CLK_EDGE_RISING;
+ } if (!strcasecmp(optarg, "falling")) {
+ out_edge = BITBANG_CLK_EDGE_FALLING;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'p':
+ preamble = 1;
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+ }
+
+ if (mdc < 0 || mdio < 0) {
+ usage();
+ exit(-1);
+ }
+
+ if (optind + 2 >= argc) {
+ usage();
+ exit(-1);
+ }
+
+ /* read or write */
+ if (!strcasecmp(argv[optind], "read")) {
+ is_write = 0;
+ } else if (!strcasecmp(argv[optind], "write")) {
+ is_write = 1;
+ } else {
+ usage();
+ exit(-1);
+ }
+
+ /* phy address, 5 bits only, so must be <= 0x1f */
+ phy_addr = strtoul(argv[optind + 1], NULL, 0);
+ if (phy_addr > 0x1f) {
+ usage();
+ exit(-1);
+ }
+
+ /* register address, 5 bits only, so must be <= 0x1f */
+ reg_addr = strtoul(argv[optind + 2], NULL, 0);
+ if (reg_addr > 0x1f) {
+ usage();
+ exit(-1);
+ }
+
+ /* data */
+ if (is_write) {
+ if ((!binary && (optind + 4 != argc)) ||
+ (binary && (optind + 3 != argc))) {
+ usage();
+ exit(-1);
+ }
+ if (binary) {
+ uint16_t temp = 0;
+ if (fread(&temp, sizeof(temp), 1, stdin) != 1) {
+ usage();
+ exit(-1);
+ }
+ data = htons(temp);
+ } else {
+ data = strtoul(argv[optind + 3], NULL, 0);
+ }
+ if (data > 0xFFFF) {
+ usage();
+ exit(-1);
+ }
+ } else {
+ if ((!binary && (optind + 3 != argc)) ||
+ (binary && (optind + 2 != argc))) {
+ usage();
+ exit(-1);
+ }
+ }
+
+ /* open all gpio */
+ memset(&ctx, sizeof(ctx), 0);
+ gpio_init_default(&ctx.m_mdc);
+ gpio_init_default(&ctx.m_mdio);
+ if (gpio_open(&ctx.m_mdc, mdc) || gpio_open(&ctx.m_mdio, mdio)) {
+ goto out;
+ }
+
+ if (gpio_change_direction(&ctx.m_mdc, GPIO_DIRECTION_OUT)
+ || gpio_change_direction(&ctx.m_mdio, GPIO_DIRECTION_OUT)) {
+ goto out;
+ }
+
+ bitbang_init_default(&init);
+ init.bbi_clk_start = mdc_start;
+ init.bbi_data_out = out_edge;
+ init.bbi_data_in = in_edge;
+ init.bbi_freq = 1000 * 1000; /* 1M Hz */
+ init.bbi_pin_f = mdio_pin_f;
+ init.bbi_context = &ctx;
+ hdl = bitbang_open(&init);
+ if (!hdl) {
+ goto out;
+ }
+
+ if (is_write) {
+ buf[0] = (data >> 8) & 0xFF;
+ buf[1] = data & 0xFF;
+ io.bbio_out_bits = 16;
+ io.bbio_dout = buf;
+ io.bbio_in_bits = 0;
+ io.bbio_din = NULL;
+ } else {
+ io.bbio_in_bits = 16;
+ io.bbio_din = buf;
+ io.bbio_out_bits = 0;
+ io.bbio_dout = NULL;
+ }
+
+ /* preamble, 32b */
+ buf_p = buf;
+ n_bits = 0;
+ if (preamble) {
+ /* 32 bit of 1 for preamble */
+ for (i = 0; i < 4; i++) {
+ *buf_p++ = 0xFF;
+ }
+ n_bits += 32;
+ }
+
+ /*
+ * MDIO transaction header is:
+ * 2b START, 2b OPER CODE, 5b PHY ADDR, 5b register addr, 2b TURNROUND
+ */
+ *buf_p++ = (START_OF_FRAME << 6) | (((is_write) ? OP_WRITE : OP_READ) << 4)
+ | ((phy_addr >> 1) & 0xF);
+ *buf_p++ = ((phy_addr & 0x1) << 7) | ((reg_addr & 0x1F) << 2) | TURNAROUND;
+ if (is_write) {
+ *buf_p++ = (data >> 8) & 0xFF;
+ *buf_p++ = data & 0xFF;
+ /* total # of bits is transaction header + 2 bytes to write */
+ n_bits += 2 + 2 + 5 + 5 + 2 + 16;
+ } else {
+ /* for read, master does not send TR, so, n_bits should not include TR */
+ n_bits += 2 + 2 + 5 + 5;
+ }
+
+ memset(&io, sizeof(io), 0);
+ io.bbio_out_bits = n_bits;
+ io.bbio_dout = buf;
+ io.bbio_in_bits = 0;
+ io.bbio_din = NULL;
+
+ rc = bitbang_io(hdl, &io);
+ if (rc != 0) {
+ goto out;
+ }
+
+ /* for read, need to do another io for (2b TR + 16b data) reading */
+ if (!is_write) {
+ /* first, change the MDIO to input */
+ gpio_change_direction(&ctx.m_mdio, GPIO_DIRECTION_IN);
+ /* then, run the clock for read */
+ memset(&io, sizeof(io), 0);
+ io.bbio_out_bits = 0;
+ io.bbio_dout = NULL;;
+ io.bbio_in_bits = 18;
+ io.bbio_din = buf;
+
+ rc = bitbang_io(hdl, &io);
+ if (rc != 0) {
+ goto out;
+ }
+
+ data = ((buf[0] << 2) | (buf[1] >> 6)) & 0xFF;
+ data <<= 8;
+ data |= ((buf[1] << 2) | (buf[2] >> 6)) & 0xFF;
+ }
+
+ if (binary) {
+ if (!is_write) {
+ uint16_t temp = ntohs(data);
+ fwrite(&temp, sizeof(temp), 1, stdout);
+ }
+ } else {
+ printf("%s: 0x%02x\n", (is_write) ? "Wrote" : "Read", data);
+ }
+
+ out:
+ if (hdl) {
+ bitbang_close(hdl);
+ }
+ gpio_close(&ctx.m_mdc);
+ gpio_close(&ctx.m_mdio);
+
+ return 0;
+}
diff --git a/common/recipes-utils/bitbang/files/src/spi_bb.c b/common/recipes-utils/bitbang/files/src/spi_bb.c
new file mode 100644
index 0000000..2125877
--- /dev/null
+++ b/common/recipes-utils/bitbang/files/src/spi_bb.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+//#define DEBUG
+//#define VERBOSE
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <openbmc/gpio.h>
+#include <openbmc/log.h>
+
+#include "bitbang.h"
+
+void usage()
+{
+ fprintf(stderr,
+ "Usage:\n"
+ "spi-bb: -s <GPIO for CS> [-S <HIGH|low>]\n"
+ " -c <GPIO for CLK> [-C <HIGH|low>]\n"
+ " -o <GPIO for MOSI> [-O <rising|FALLING>]\n"
+ " -i <GPIO for MISO> [-I <RISING|falling>]\n"
+ " [-b]\n"
+ " < [-r <number of bits to read>]\n"
+ " [-w <number of bits to write> <byte 1> [... byte N]>\n\n"
+ "Note: If both '-r' and '-w' are provided, 'write' will be performed\n"
+ " before 'read'.\n");
+}
+
+typedef struct {
+ gpio_st sc_clk;
+ gpio_st sc_mosi;
+ gpio_st sc_miso;
+} spi_context_st;
+
+bitbang_pin_value_en spi_pin_f(
+ bitbang_pin_type_en pin, bitbang_pin_value_en value, void *context)
+{
+ spi_context_st *ctx = (spi_context_st *)context;
+ gpio_st *gpio;
+ bitbang_pin_value_en res;
+
+ switch (pin) {
+ case BITBANG_CLK_PIN:
+ gpio = &ctx->sc_clk;
+ break;
+ case BITBANG_DATA_IN:
+ gpio = &ctx->sc_miso;
+ break;
+ case BITBANG_DATA_OUT:
+ gpio = &ctx->sc_mosi;
+ break;
+ }
+ if (pin == BITBANG_DATA_IN) {
+ res = gpio_read(gpio) ? BITBANG_PIN_HIGH : BITBANG_PIN_LOW;
+ } else {
+ res = value;
+ gpio_write(gpio, ((res == BITBANG_PIN_HIGH)
+ ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW));
+ }
+ return res;
+}
+
+int main(int argc, char * const argv[])
+{
+ bitbang_init_st init;
+ bitbang_handle_st *hdl = NULL;
+ int cs = -1, clk = -1, in = -1, out = -1;
+ gpio_st cs_gpio;
+ int opt;
+ int is_write = 0;
+ int is_read = 0;
+ int read_bits = 0;
+ int write_bits = 0;
+ int read_bytes = 0;
+ int write_bytes = 0;
+ int i;
+ uint8_t *read_buf = NULL;;
+ uint8_t *write_buf = NULL;;
+ bitbang_clk_edge_en dout_edge = BITBANG_CLK_EDGE_FALLING;
+ bitbang_clk_edge_en din_edge = BITBANG_CLK_EDGE_RISING;
+ bitbang_pin_value_en clk_start = BITBANG_PIN_HIGH;
+ bitbang_pin_value_en cs_value = BITBANG_PIN_HIGH;
+ spi_context_st ctx;
+ bitbang_io_st io;
+ int rc = 0;
+ int binary = 0;
+
+ memset(&ctx, sizeof(ctx), 0);
+ gpio_init_default(&ctx.sc_clk);
+ gpio_init_default(&ctx.sc_mosi);
+ gpio_init_default(&ctx.sc_miso);
+ gpio_init_default(&cs_gpio);
+
+ while ((opt = getopt(argc, argv, "bs:S:c:C:o:O:i:I:w:r:")) != -1) {
+ switch (opt) {
+ case 'b':
+ binary = 1;
+ break;
+ case 's':
+ cs = atoi(optarg);
+ break;
+ case 'S':
+ if (!strcmp(optarg, "high")) {
+ cs_value = BITBANG_PIN_HIGH;
+ } else if (!strcmp(optarg, "low")) {
+ cs_value = BITBANG_PIN_LOW;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'c':
+ clk = atoi(optarg);
+ break;
+ case 'C':
+ if (!strcasecmp(optarg, "high")) {
+ clk_start = BITBANG_PIN_HIGH;
+ } else if (!strcasecmp(optarg, "low")) {
+ clk_start = BITBANG_PIN_LOW;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'o':
+ out = atoi(optarg);
+ break;
+ case 'O':
+ if (!strcasecmp(optarg, "rising")) {
+ dout_edge = BITBANG_CLK_EDGE_RISING;
+ } else if (!strcasecmp(optarg, "falling")) {
+ dout_edge = BITBANG_CLK_EDGE_FALLING;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'i':
+ in = atoi(optarg);
+ break;
+ case 'I':
+ if (!strcasecmp(optarg, "rising")) {
+ din_edge = BITBANG_CLK_EDGE_RISING;
+ } else if (!strcasecmp(optarg, "falling")) {
+ din_edge = BITBANG_CLK_EDGE_FALLING;
+ } else {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'w':
+ is_write = 1;
+ write_bits = atoi(optarg);
+ if (write_bits <= 0) {
+ usage();
+ exit(-1);
+ }
+ break;
+ case 'r':
+ is_read = 1;
+ read_bits = atoi(optarg);
+ if (read_bits <= 0) {
+ usage();
+ exit(-1);
+ }
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+ }
+
+ if (clk < 0 || in < 0 || out < 0) {
+ usage();
+ exit(-1);
+ }
+
+ if ((!is_read && !is_write)) {
+ usage();
+ exit(-1);
+ }
+
+ write_bytes = ((write_bits + 7) / 8);
+ if (write_bytes) {
+ write_buf = calloc(write_bytes, sizeof(uint8_t));
+ if (!write_buf) {
+ goto out;
+ }
+ if (binary) {
+ size_t written_bytes;
+ written_bytes = fread(write_buf, sizeof(*write_buf), write_bytes, stdin);
+ if( written_bytes != write_bytes ) {
+ goto out;
+ }
+ } else {
+ for (i = 0; i < write_bytes && i + optind < argc; i++) {
+ write_buf[i] = strtoul(argv[i + optind], NULL, 0);
+ }
+ }
+ }
+
+ read_bytes = ((read_bits + 7) / 8);
+ if (read_bytes) {
+ read_buf = calloc(read_bytes, sizeof(uint8_t));
+ if (!read_buf) {
+ goto out;
+ }
+ }
+
+ if (gpio_open(&ctx.sc_clk, clk) || gpio_open(&ctx.sc_miso, in)
+ || gpio_open(&ctx.sc_mosi, out)) {
+ goto out;
+ }
+
+ /* change GPIO directions, only MISO is input, all others are output */
+ if (gpio_change_direction(&ctx.sc_clk, GPIO_DIRECTION_OUT)
+ || gpio_change_direction(&ctx.sc_miso, GPIO_DIRECTION_IN)
+ || gpio_change_direction(&ctx.sc_mosi, GPIO_DIRECTION_OUT)) {
+ goto out;
+ }
+
+ if (cs != -1) {
+ if (gpio_open(&cs_gpio, cs)) {
+ goto out;
+ }
+ if (gpio_change_direction(&cs_gpio, GPIO_DIRECTION_OUT)) {
+ goto out;
+ }
+ }
+
+ bitbang_init_default(&init);
+ init.bbi_clk_start = clk_start;
+ init.bbi_data_out = dout_edge;
+ init.bbi_data_in = din_edge;
+ init.bbi_freq = 1000 * 1000; /* 1M Hz */
+ init.bbi_pin_f = spi_pin_f;
+ init.bbi_context = &ctx;
+
+ hdl = bitbang_open(&init);
+ if (!hdl) {
+ goto out;
+ }
+
+ if (cs != -1) {
+ /* have chip select */
+ gpio_write(&cs_gpio, ((cs_value == BITBANG_PIN_HIGH)
+ ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW));
+ }
+
+ memset(&io, sizeof(io), 0);
+ io.bbio_in_bits = read_bits;
+ io.bbio_din = read_buf;
+ io.bbio_out_bits = write_bits;
+ io.bbio_dout = write_buf;
+
+ rc = bitbang_io(hdl, &io);
+ if (rc != 0) {
+ goto out;
+ }
+
+ if (binary) {
+ fwrite(read_buf, sizeof(*read_buf), read_bytes, stdout);
+ } else {
+ if (write_bits) {
+ printf("Wrote %u bits:", write_bits);
+ for (i = 0; i < write_bytes; i++) {
+ printf(" %02x", write_buf[i]);
+ }
+ printf("\n");
+ }
+
+ if (read_bits) {
+ printf("Read %u bits:", read_bits);
+ for (i = 0; i < read_bytes; i++) {
+ printf(" %02x", read_buf[i]);
+ }
+ printf("\n");
+ }
+ }
+
+ out:
+ if (hdl) {
+ bitbang_close(hdl);
+ }
+ gpio_close(&ctx.sc_clk);
+ gpio_close(&ctx.sc_miso);
+ gpio_close(&ctx.sc_mosi);
+ if (cs != -1) {
+ /* reset have chip select */
+ gpio_write(&cs_gpio, ((cs_value == BITBANG_PIN_HIGH)
+ ? GPIO_VALUE_LOW : GPIO_VALUE_HIGH));
+ gpio_close(&cs_gpio);
+ }
+
+ if (read_buf) {
+ free(read_buf);
+ }
+ if (write_buf) {
+ free(write_buf);
+ }
+ return rc;
+}
diff --git a/common/recipes-utils/flashrom/files/01-include-make-local.patch b/common/recipes-utils/flashrom/files/01-include-make-local.patch
new file mode 100644
index 0000000..660c4d6
--- /dev/null
+++ b/common/recipes-utils/flashrom/files/01-include-make-local.patch
@@ -0,0 +1,11 @@
+--- a/Makefile.orig 2015-08-05 17:10:45.945870520 -0700
++++ b/Makefile 2015-08-05 17:11:01.212895144 -0700
+@@ -20,6 +20,8 @@
+
+ PROGRAM = flashrom
+
++include make.local
++
+ ###############################################################################
+ # Defaults for the toolchain.
+
diff --git a/common/recipes-utils/flashrom/files/flashrom-0.9.8/make.local b/common/recipes-utils/flashrom/files/flashrom-0.9.8/make.local
new file mode 100644
index 0000000..54f4213
--- /dev/null
+++ b/common/recipes-utils/flashrom/files/flashrom-0.9.8/make.local
@@ -0,0 +1,9 @@
+CONFIG_BUSPIRATE_SPI = no
+CONFIG_SERPROG = no
+CONFIG_PONY_SPI = no
+CONFIG_DEDIPROG = no
+CONFIG_FT2232_SPI = no
+CONFIG_USBBLASTER_SPI = no
+CONFIG_PICKIT2_SPI = no
+CONFIG_LINUX_SPI = yes
+CONFIG_MSTARDDC_SPI = no
diff --git a/common/recipes-utils/flashrom/flashrom_0.9.8.bb b/common/recipes-utils/flashrom/flashrom_0.9.8.bb
new file mode 100644
index 0000000..a65a7c0
--- /dev/null
+++ b/common/recipes-utils/flashrom/flashrom_0.9.8.bb
@@ -0,0 +1,18 @@
+DESCRIPTION = "flashrom is a utility for identifying, reading, writing, verifying and erasing flash chips"
+LICENSE = "GPLv2"
+HOMEPAGE = "http://flashrom.org"
+
+LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe"
+DEPENDS = "pciutils"
+
+SRC_URI = "http://download.flashrom.org/releases/flashrom-${PV}.tar.bz2 \
+ file://flashrom-${PV}/make.local \
+ file://01-include-make-local.patch \
+ "
+
+Src_URI[md5sum] = "ac513076b63ab7eb411a7694bb8f6fda"
+SRC_URI[sha256sum] = "13dc7c895e583111ecca370363a3527d237d178a134a94b20db7df177c05f934"
+
+do_install() {
+ oe_runmake PREFIX=${prefix} DESTDIR=${D} install
+}
diff --git a/common/recipes-utils/jbi/files/code/COPYING b/common/recipes-utils/jbi/files/code/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/common/recipes-utils/jbi/files/code/Makefile b/common/recipes-utils/jbi/files/code/Makefile
new file mode 100644
index 0000000..ca84b02
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+all: jbi
+
+jbi: jbicomp.o jbijtag.o jbimain.o jbistub.o
+ $(CC) -g -o $@ $^ $(LDFLAGS) -lgpio
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o jbi
diff --git a/common/recipes-utils/jbi/files/code/jbicomp.c b/common/recipes-utils/jbi/files/code/jbicomp.c
new file mode 100644
index 0000000..99ba515
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbicomp.c
@@ -0,0 +1,416 @@
+/****************************************************************************/
+/* */
+/* Module: jbicomp.c */
+/* */
+/* Copyright (C) Altera Corporation 1997-2001 */
+/* */
+/* Description: Contains the code for compressing and uncompressing */
+/* Boolean array data. */
+/* */
+/* This algorithm works by searching previous bytes in the */
+/* data that match the current data. If a match is found, */
+/* then the offset and length of the matching data can */
+/* replace the actual data in the output. */
+/* */
+/* Revisions: 2.2 fixed /W4 warnings */
+/* */
+/****************************************************************************/
+
+#include "jbiport.h"
+#include "jbiexprt.h"
+#include "jbicomp.h"
+
+#define SHORT_BITS 16
+#define CHAR_BITS 8
+#define DATA_BLOB_LENGTH 3
+#define MATCH_DATA_LENGTH 8192
+#define JBI_ACA_REQUEST_SIZE 1024
+#define JBI_ACA_BUFFER_SIZE (MATCH_DATA_LENGTH + JBI_ACA_REQUEST_SIZE)
+
+unsigned long jbi_in_length = 0L;
+unsigned long jbi_in_index = 0L; /* byte index into compressed array */
+unsigned int jbi_bits_avail = CHAR_BITS;
+
+#if PORT == DOS
+int jbi_current_variable_id = -1;
+int jbi_current_page = -1;
+int jbi_version = 0;
+unsigned long jbi_out_length = 0L;
+unsigned int jbi_out_index = 0; /* byte index into jbi_aca_out_buffer[] */
+unsigned long jbi_aca_in_offset = 0L;
+unsigned char jbi_aca_out_buffer[JBI_ACA_BUFFER_SIZE];
+#endif
+
+/****************************************************************************/
+/* */
+/* The following functions implement incremental decompression of Boolean */
+/* array data, using a small memory window. */
+/* */
+/* This algorithm works by searching previous bytes in the data that match */
+/* the current data. If a match is found, then the offset and length of */
+/* the matching data can replace the actual data in the output. */
+/* */
+/* Memory usage is reduced by maintaining a "window" buffer which contains */
+/* the uncompressed data for one 8K page, plus some extra amount specified */
+/* by JBI_ACA_REQUEST_SIZE. The function jbi_uncompress_page() is used to */
+/* request a subrange of the uncompressed data, starting at a particular */
+/* bit position and extending a maximum of JBI_ACA_REQUEST_SIZE bytes. */
+/* */
+/****************************************************************************/
+
+/****************************************************************************/
+/* */
+
+unsigned int jbi_bits_required(unsigned int n)
+
+/* */
+/* Description: Calculate the minimum number of bits required to */
+/* represent n. */
+/* */
+/* Returns: Number of bits. */
+/* */
+/****************************************************************************/
+{
+ unsigned int result = SHORT_BITS;
+
+ if (n == 0)
+ {
+ result = 1;
+ }
+ else
+ {
+ /* Look for the highest non-zero bit position */
+ while ((n & (1 << (SHORT_BITS - 1))) == 0)
+ {
+ n <<= 1;
+ --result;
+ }
+ }
+
+ return (result);
+}
+
+/****************************************************************************/
+/* */
+
+unsigned int jbi_read_packed
+(
+#if PORT!=DOS
+ unsigned char *buffer,
+#endif
+ unsigned int bits
+)
+
+/* */
+/* Description: Read the next value from the input array "buffer". */
+/* Read only "bits" bits from the array. The amount of */
+/* bits that have already been read from "buffer" is */
+/* stored internally to this function. */
+/* */
+/* Returns: Up to 16 bit value. -1 if buffer overrun. */
+/* */
+/****************************************************************************/
+{
+ unsigned int result = 0;
+ unsigned int shift = 0;
+ unsigned int databyte = 0;
+
+ while (bits > 0)
+ {
+#if PORT==DOS
+ databyte = GET_BYTE(jbi_aca_in_offset + jbi_in_index);
+#else
+ databyte = buffer[jbi_in_index];
+#endif
+ result |= (((databyte >> (CHAR_BITS - jbi_bits_avail))
+ & (0xFF >> (CHAR_BITS - jbi_bits_avail))) << shift);
+
+ if (bits <= jbi_bits_avail)
+ {
+ result &= (0xFFFF >> (SHORT_BITS - (bits + shift)));
+ jbi_bits_avail -= bits;
+ bits = 0;
+ }
+ else
+ {
+ ++jbi_in_index;
+ shift += jbi_bits_avail;
+ bits -= jbi_bits_avail;
+ jbi_bits_avail = CHAR_BITS;
+ }
+ }
+
+ return (result);
+}
+
+#if PORT==DOS
+
+/****************************************************************************/
+/* */
+
+void jbi_uncompress_next_page(int version)
+
+/* */
+/* Description: Uncompresses one page of compressed data, using */
+/* data page as reference for repeated sections. */
+/* Overwrites previous page of data in buffer. */
+/* */
+/* Returns: TRUE for success, FALSE if error encountered */
+/* */
+/****************************************************************************/
+{
+ unsigned int i, j, offset, length;
+ unsigned int end_index;
+ unsigned long tmp_in_index = jbi_in_index;
+ unsigned int tmp_out_index = jbi_out_index;
+ unsigned int tmp_bits_avail = jbi_bits_avail;
+ unsigned int prev[3];
+ unsigned long long_end;
+ unsigned int match_data_length = MATCH_DATA_LENGTH;
+
+ if (version > 0) --match_data_length;
+
+ if (jbi_current_page < 0)
+ {
+ /* this is the first page of the array */
+ jbi_current_page = 0;
+ jbi_in_index = 4; /* skip over length field */
+ jbi_out_index = 0;
+ end_index = (jbi_out_length < JBI_ACA_BUFFER_SIZE) ?
+ (unsigned int) jbi_out_length : JBI_ACA_BUFFER_SIZE;
+ }
+ else
+ {
+ /* this is not the first page */
+ ++jbi_current_page;
+ jbi_out_index -= MATCH_DATA_LENGTH;
+ long_end = jbi_out_length -
+ ((long) jbi_current_page * (long) MATCH_DATA_LENGTH);
+ end_index = (long_end < JBI_ACA_BUFFER_SIZE) ?
+ (unsigned int) long_end : JBI_ACA_BUFFER_SIZE;
+
+ /* copy extra data from end of circular buffer to beginning */
+ for (i = 0; i < jbi_out_index; ++i)
+ {
+ jbi_aca_out_buffer[i] = jbi_aca_out_buffer[i + MATCH_DATA_LENGTH];
+ }
+ }
+
+ while (jbi_out_index < end_index)
+ {
+ /* save state so we can undo the last packet when we reach the end */
+ tmp_in_index = jbi_in_index;
+ tmp_out_index = jbi_out_index;
+ tmp_bits_avail = jbi_bits_avail;
+
+ /* A 0 bit indicates literal data. */
+ if (jbi_read_packed(1) == 0)
+ {
+ for (i = 0; i < DATA_BLOB_LENGTH; ++i)
+ {
+ if (jbi_out_index < end_index)
+ {
+ if (version == 0)
+ {
+ prev[i] = jbi_aca_out_buffer[jbi_out_index] & 0xff;
+ }
+ jbi_aca_out_buffer[jbi_out_index++] =
+ (unsigned char) jbi_read_packed(CHAR_BITS);
+ }
+ }
+ }
+ else
+ {
+ /* A 1 bit indicates offset/length to follow. */
+ offset = jbi_read_packed(jbi_bits_required(
+ (jbi_current_page > 0) ? match_data_length :
+ (jbi_out_index > match_data_length ? match_data_length :
+ jbi_out_index)));
+ length = jbi_read_packed(CHAR_BITS);
+
+ if ((version == 0) && (offset == match_data_length + 3))
+ {
+ jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[0];
+ jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[1];
+ jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[2];
+ length -= 3;
+ }
+
+ for (i = 0; i < length; ++i)
+ {
+ if (jbi_out_index < end_index)
+ {
+ if (offset > jbi_out_index)
+ {
+ j = jbi_out_index + MATCH_DATA_LENGTH - offset;
+ }
+ else j = jbi_out_index - offset;
+ jbi_aca_out_buffer[jbi_out_index] = jbi_aca_out_buffer[j];
+ ++jbi_out_index;
+ }
+ }
+
+ if (version == 0)
+ {
+ prev[0] = jbi_aca_out_buffer[jbi_out_index - 3] & 0xff;
+ prev[1] = jbi_aca_out_buffer[jbi_out_index - 2] & 0xff;
+ prev[2] = jbi_aca_out_buffer[jbi_out_index - 1] & 0xff;
+ }
+ }
+ }
+
+ /* restore the state before the previous packet */
+ jbi_in_index = tmp_in_index;
+ jbi_out_index = tmp_out_index;
+ jbi_bits_avail = tmp_bits_avail;
+}
+
+/****************************************************************************/
+/* */
+
+void jbi_uncompress_page
+(
+ int variable_id,
+ int page,
+ int version
+)
+
+/* */
+/* Description: Uncompress requested page of variable data. Stores */
+/* uncompressed data in jbi_aca_out_buffer[]. */
+/* */
+/* Returns: TRUE if successful, otherwise FALSE if: */
+/* 1) variable is not a compressed array */
+/* 2) compressed data is illegal or corrupted */
+/* 3) requested page is beyond the end of the array */
+/* 4) internal error in the code */
+/* */
+/****************************************************************************/
+{
+ unsigned long symbol_table;
+ unsigned long data_section;
+ unsigned long offset;
+ unsigned long value;
+ int delta = version * 2;
+
+ if (variable_id != jbi_current_variable_id)
+ {
+ /* initialize to uncompress the desired variable */
+ symbol_table = GET_DWORD(16 + (version * 8));
+ data_section = GET_DWORD(20 + (version * 8));
+ offset = symbol_table + ((11 + delta) * variable_id);
+ value = GET_DWORD(offset + 3 + delta);
+ jbi_current_variable_id = variable_id;
+ jbi_current_page = -1;
+ jbi_bits_avail = CHAR_BITS;
+ jbi_in_length = GET_DWORD(offset + 7 + delta);
+ jbi_out_length =
+ (((unsigned long) GET_BYTE(data_section + value)) |
+ (((unsigned long) GET_BYTE(data_section + value + 1)) << 8) |
+ (((unsigned long) GET_BYTE(data_section + value + 2)) << 16) |
+ (((unsigned long) GET_BYTE(data_section + value + 3)) << 24));
+ jbi_in_index = 4; /* skip over length field */
+ jbi_out_index = 0;
+ jbi_aca_in_offset = data_section + value;
+ }
+
+ /* to look back at an earlier page, start over at the beginning */
+ if (page < jbi_current_page)
+ {
+ jbi_current_page = -1;
+ jbi_in_index = 4; /* skip over length field */
+ jbi_bits_avail = CHAR_BITS;
+ }
+
+ /* uncompress sequentially up to the desired page */
+ while (page > jbi_current_page)
+ {
+ jbi_uncompress_next_page(version);
+ }
+}
+
+#else
+
+/****************************************************************************/
+/* */
+
+unsigned long jbi_uncompress
+(
+ unsigned char *in,
+ unsigned long in_length,
+ unsigned char *out,
+ unsigned long out_length,
+ int version
+)
+
+/* */
+/* Description: Uncompress data in "in" and write result to "out". */
+/* */
+/* Returns: Length of uncompressed data. -1 if: */
+/* 1) out_length is too small */
+/* 2) Internal error in the code */
+/* 3) in doesn't contain ACA compressed data. */
+/* */
+/****************************************************************************/
+{
+ unsigned long i, j, data_length = 0L;
+ unsigned int offset, length;
+ unsigned int match_data_length = MATCH_DATA_LENGTH;
+
+ if (version > 0) --match_data_length;
+
+ jbi_in_length = in_length;
+ jbi_bits_avail = CHAR_BITS;
+ jbi_in_index = 0L;
+ for (i = 0; i < out_length; ++i) out[i] = 0;
+
+ /* Read number of bytes in data. */
+ for (i = 0; i < sizeof (in_length); ++i)
+ {
+ data_length = data_length | ((unsigned long)
+ jbi_read_packed(in, CHAR_BITS) << (i * CHAR_BITS));
+ }
+
+ if (data_length > out_length)
+ {
+ data_length = 0L;
+ }
+ else
+ {
+ i = 0;
+ while (i < data_length)
+ {
+ /* A 0 bit indicates literal data. */
+ if (jbi_read_packed(in, 1) == 0)
+ {
+ for (j = 0; j < DATA_BLOB_LENGTH; ++j)
+ {
+ if (i < data_length)
+ {
+ out[i] = (unsigned char) jbi_read_packed(in, CHAR_BITS);
+ i++;
+ }
+ }
+ }
+ else
+ {
+ /* A 1 bit indicates offset/length to follow. */
+ offset = jbi_read_packed(in, jbi_bits_required((short) (i > match_data_length ? match_data_length : i)));
+ length = jbi_read_packed(in, CHAR_BITS);
+
+ for (j = 0; j < length; ++j)
+ {
+ if (i < data_length)
+ {
+ out[i] = out[i - offset];
+ i++;
+ }
+ }
+ }
+ }
+ }
+
+ return (data_length);
+}
+
+#endif
diff --git a/common/recipes-utils/jbi/files/code/jbicomp.h b/common/recipes-utils/jbi/files/code/jbicomp.h
new file mode 100644
index 0000000..382995d
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbicomp.h
@@ -0,0 +1,37 @@
+/****************************************************************************/
+/* */
+/* Module: jbicomp.h */
+/* */
+/* Copyright (C) Altera Corporation 1997-2001 */
+/* */
+/* Description: Contains the function prototypes for compressing */
+/* and uncompressing Boolean array data. */
+/* */
+/****************************************************************************/
+
+#ifndef INC_JBICOMP_H
+#define INC_JBICOMP_H
+
+#if PORT==DOS
+
+void jbi_uncompress_page
+(
+ int variable_id,
+ int page,
+ int version
+);
+
+#else
+
+unsigned long jbi_uncompress
+(
+ unsigned char *in,
+ unsigned long in_length,
+ unsigned char *out,
+ unsigned long out_length,
+ int version
+);
+
+#endif /* PORT==DOS */
+
+#endif /* INC_JBICOMP_H */
diff --git a/common/recipes-utils/jbi/files/code/jbiexprt.h b/common/recipes-utils/jbi/files/code/jbiexprt.h
new file mode 100644
index 0000000..6d6a401
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbiexprt.h
@@ -0,0 +1,224 @@
+/****************************************************************************/
+/* */
+/* Module: jbiexprt.h */
+/* */
+/* Copyright (C) Altera Corporation 1998-2001 */
+/* */
+/* Description: Jam STAPL ByteCode Player Export Header File */
+/* */
+/* Revisions: */
+/* */
+/****************************************************************************/
+
+#ifndef INC_JBIEXPRT_H
+#define INC_JBIEXPRT_H
+
+/****************************************************************************/
+/* */
+/* Return codes from most JBI functions */
+/* */
+/****************************************************************************/
+
+#define JBI_RETURN_TYPE int
+
+#define JBIC_SUCCESS 0
+#define JBIC_OUT_OF_MEMORY 1
+#define JBIC_IO_ERROR 2
+/* #define JAMC_SYNTAX_ERROR 3 */
+#define JBIC_UNEXPECTED_END 4
+#define JBIC_UNDEFINED_SYMBOL 5
+/* #define JAMC_REDEFINED_SYMBOL 6 */
+#define JBIC_INTEGER_OVERFLOW 7
+#define JBIC_DIVIDE_BY_ZERO 8
+#define JBIC_CRC_ERROR 9
+#define JBIC_INTERNAL_ERROR 10
+#define JBIC_BOUNDS_ERROR 11
+/* #define JAMC_TYPE_MISMATCH 12 */
+/* #define JAMC_ASSIGN_TO_CONST 13 */
+/* #define JAMC_NEXT_UNEXPECTED 14 */
+/* #define JAMC_POP_UNEXPECTED 15 */
+/* #define JAMC_RETURN_UNEXPECTED 16 */
+/* #define JAMC_ILLEGAL_SYMBOL 17 */
+#define JBIC_VECTOR_MAP_FAILED 18
+#define JBIC_USER_ABORT 19
+#define JBIC_STACK_OVERFLOW 20
+#define JBIC_ILLEGAL_OPCODE 21
+/* #define JAMC_PHASE_ERROR 22 */
+/* #define JAMC_SCOPE_ERROR 23 */
+#define JBIC_ACTION_NOT_FOUND 24
+
+/****************************************************************************/
+/* */
+/* Macro Definitions */
+/* */
+/****************************************************************************/
+
+/*
+* For DOS port, program data is stored in a set of 16K pages, accessed
+* through a pointer table. For 32-bit version, the buffer is continuous.
+* The macro GET_BYTE gets a single byte for either case.
+*/
+#if PORT==DOS
+#define PROGRAM_PTR unsigned char **
+#else
+#define PROGRAM_PTR unsigned char *
+#endif
+
+#if PORT==DOS
+#define GET_BYTE(x) (jbi_program[(x) >> 14L][(x) & 0x3fffL])
+#else
+#define GET_BYTE(x) (program[x])
+#endif
+
+#define GET_WORD(x) \
+ (((((unsigned short) GET_BYTE(x)) << 8) & 0xFF00) | \
+ (((unsigned short) GET_BYTE((x)+1)) & 0x00FF))
+
+#define GET_DWORD(x) \
+ (((((unsigned long) GET_BYTE(x)) << 24L) & 0xFF000000L) | \
+ ((((unsigned long) GET_BYTE((x)+1)) << 16L) & 0x00FF0000L) | \
+ ((((unsigned long) GET_BYTE((x)+2)) << 8L) & 0x0000FF00L) | \
+ (((unsigned long) GET_BYTE((x)+3)) & 0x000000FFL))
+
+/****************************************************************************/
+/* */
+/* Structured Types */
+/* */
+/****************************************************************************/
+
+typedef struct JBI_PROCINFO_STRUCT
+{
+ char *name;
+ unsigned char attributes;
+ struct JBI_PROCINFO_STRUCT *next;
+}
+JBI_PROCINFO;
+
+/****************************************************************************/
+/* */
+/* Global Data Prototypes */
+/* */
+/****************************************************************************/
+
+#if PORT==DOS
+extern unsigned char jbi_aca_out_buffer[8192 + 1024];
+#endif
+
+extern PROGRAM_PTR jbi_program;
+
+extern char *jbi_workspace;
+
+extern long jbi_workspace_size;
+
+/****************************************************************************/
+/* */
+/* Function Prototypes */
+/* */
+/****************************************************************************/
+
+JBI_RETURN_TYPE jbi_execute
+(
+ PROGRAM_PTR program,
+ long program_size,
+ char *workspace,
+ long workspace_size,
+ char *action,
+ char **init_list,
+ int reset_jtag,
+ long *error_address,
+ int *exit_code,
+ int *format_version
+);
+
+JBI_RETURN_TYPE jbi_get_note
+(
+ PROGRAM_PTR program,
+ long program_size,
+ long *offset,
+ char *key,
+ char *value,
+ int length
+);
+
+JBI_RETURN_TYPE jbi_check_crc
+(
+ PROGRAM_PTR program,
+ long program_size,
+ unsigned short *expected_crc,
+ unsigned short *actual_crc
+);
+
+JBI_RETURN_TYPE jbi_get_file_info
+(
+ PROGRAM_PTR program,
+ long program_size,
+ int *format_version,
+ int *action_count,
+ int *procedure_count
+);
+
+JBI_RETURN_TYPE jbi_get_action_info
+(
+ PROGRAM_PTR program,
+ long program_size,
+ int index,
+ char **name,
+ char **description,
+ JBI_PROCINFO **procedure_list
+);
+
+int jbi_jtag_io
+(
+ int tms,
+ int tdi,
+ int read_tdo
+);
+
+void jbi_message
+(
+ char *message_text
+);
+
+void jbi_export_integer
+(
+ char *key,
+ long value
+);
+
+void jbi_export_boolean_array
+(
+ char *key,
+ unsigned char *data,
+ long count
+);
+
+void jbi_delay
+(
+ long microseconds
+);
+
+int jbi_vector_map
+(
+ int signal_count,
+ char **signals
+);
+
+int jbi_vector_io
+(
+ int signal_count,
+ long *dir_vect,
+ long *data_vect,
+ long *capture_vect
+);
+
+void *jbi_malloc
+(
+ unsigned int size
+);
+
+void jbi_free
+(
+ void *ptr
+);
+
+#endif /* INC_JBIEXPRT_H */
diff --git a/common/recipes-utils/jbi/files/code/jbijtag.c b/common/recipes-utils/jbi/files/code/jbijtag.c
new file mode 100644
index 0000000..728ab6a
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbijtag.c
@@ -0,0 +1,1675 @@
+/****************************************************************************/
+/* */
+/* Module: jbijtag.c */
+/* */
+/* Copyright (C) Altera Corporation 1998-2001 */
+/* */
+/* Description: Contains JTAG interface functions */
+/* */
+/* Revisions: 2.2 updated state transition paths */
+/* 2.0 added multi-page scan code for 16-bit PORT */
+/* */
+/****************************************************************************/
+
+#include "jbiport.h"
+#include "jbiexprt.h"
+#include "jbicomp.h"
+#include "jbijtag.h"
+
+#define NULL 0
+
+char *jbi_workspace = NULL;
+long jbi_workspace_size = 0L;
+
+/****************************************************************************/
+/* */
+/* Enumerated Types */
+/* */
+/****************************************************************************/
+
+/* maximum JTAG IR and DR lengths (in bits) */
+#define JBIC_MAX_JTAG_IR_PREAMBLE 256
+#define JBIC_MAX_JTAG_IR_POSTAMBLE 256
+#define JBIC_MAX_JTAG_IR_LENGTH 512
+#define JBIC_MAX_JTAG_DR_PREAMBLE 1024
+#define JBIC_MAX_JTAG_DR_POSTAMBLE 1024
+#define JBIC_MAX_JTAG_DR_LENGTH 2048
+
+/*
+* Global variable to store the current JTAG state
+*/
+JBIE_JTAG_STATE jbi_jtag_state = JBI_ILLEGAL_JTAG_STATE;
+
+/*
+* Store current stop-state for DR and IR scan commands
+*/
+JBIE_JTAG_STATE jbi_drstop_state = IDLE;
+JBIE_JTAG_STATE jbi_irstop_state = IDLE;
+
+/*
+* Store current padding values
+*/
+unsigned int jbi_dr_preamble = 0;
+unsigned int jbi_dr_postamble = 0;
+unsigned int jbi_ir_preamble = 0;
+unsigned int jbi_ir_postamble = 0;
+unsigned int jbi_dr_length = 0;
+unsigned int jbi_ir_length = 0;
+unsigned char *jbi_dr_preamble_data = NULL;
+unsigned char *jbi_dr_postamble_data = NULL;
+unsigned char *jbi_ir_preamble_data = NULL;
+unsigned char *jbi_ir_postamble_data = NULL;
+unsigned char *jbi_dr_buffer = NULL;
+unsigned char *jbi_ir_buffer = NULL;
+
+/*
+* This structure shows, for each JTAG state, which state is reached after
+* a single TCK clock cycle with TMS high or TMS low, respectively. This
+* describes all possible state transitions in the JTAG state machine.
+*/
+struct JBIS_JTAG_MACHINE
+{
+ JBIE_JTAG_STATE tms_high;
+ JBIE_JTAG_STATE tms_low;
+} jbi_jtag_state_transitions[] =
+{
+/* RESET */ { RESET, IDLE },
+/* IDLE */ { DRSELECT, IDLE },
+/* DRSELECT */ { IRSELECT, DRCAPTURE },
+/* DRCAPTURE */ { DREXIT1, DRSHIFT },
+/* DRSHIFT */ { DREXIT1, DRSHIFT },
+/* DREXIT1 */ { DRUPDATE, DRPAUSE },
+/* DRPAUSE */ { DREXIT2, DRPAUSE },
+/* DREXIT2 */ { DRUPDATE, DRSHIFT },
+/* DRUPDATE */ { DRSELECT, IDLE },
+/* IRSELECT */ { RESET, IRCAPTURE },
+/* IRCAPTURE */ { IREXIT1, IRSHIFT },
+/* IRSHIFT */ { IREXIT1, IRSHIFT },
+/* IREXIT1 */ { IRUPDATE, IRPAUSE },
+/* IRPAUSE */ { IREXIT2, IRPAUSE },
+/* IREXIT2 */ { IRUPDATE, IRSHIFT },
+/* IRUPDATE */ { DRSELECT, IDLE }
+};
+
+/*
+* This table contains the TMS value to be used to take the NEXT STEP on
+* the path to the desired state. The array index is the current state,
+* and the bit position is the desired endstate. To find out which state
+* is used as the intermediate state, look up the TMS value in the
+* jbi_jtag_state_transitions[] table.
+*/
+unsigned short jbi_jtag_path_map[16] =
+{
+/* RST RTI SDRS CDR SDR E1DR PDR E2DR */
+ 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF,
+/* UDR SIRS CIR SIR E1IR PIR E2IR UIR */
+ 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD
+};
+
+/*
+* Flag bits for jbi_jtag_io() function
+*/
+#define TMS_HIGH 1
+#define TMS_LOW 0
+#define TDI_HIGH 1
+#define TDI_LOW 0
+#define READ_TDO 1
+#define IGNORE_TDO 0
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_init_jtag()
+
+/* */
+/****************************************************************************/
+{
+ /* initial JTAG state is unknown */
+ jbi_jtag_state = JBI_ILLEGAL_JTAG_STATE;
+
+ /* initialize global variables to default state */
+ jbi_drstop_state = IDLE;
+ jbi_irstop_state = IDLE;
+ jbi_dr_preamble = 0;
+ jbi_dr_postamble = 0;
+ jbi_ir_preamble = 0;
+ jbi_ir_postamble = 0;
+ jbi_dr_length = 0;
+ jbi_ir_length = 0;
+
+ if (jbi_workspace != NULL)
+ {
+ jbi_dr_preamble_data = (unsigned char *) jbi_workspace;
+ jbi_dr_postamble_data = &jbi_dr_preamble_data[JBIC_MAX_JTAG_DR_PREAMBLE / 8];
+ jbi_ir_preamble_data = &jbi_dr_postamble_data[JBIC_MAX_JTAG_DR_POSTAMBLE / 8];
+ jbi_ir_postamble_data = &jbi_ir_preamble_data[JBIC_MAX_JTAG_IR_PREAMBLE / 8];
+ jbi_dr_buffer = &jbi_ir_postamble_data[JBIC_MAX_JTAG_IR_POSTAMBLE / 8];
+ jbi_ir_buffer = &jbi_dr_buffer[JBIC_MAX_JTAG_DR_LENGTH / 8];
+ }
+ else
+ {
+ jbi_dr_preamble_data = NULL;
+ jbi_dr_postamble_data = NULL;
+ jbi_ir_preamble_data = NULL;
+ jbi_ir_postamble_data = NULL;
+ jbi_dr_buffer = NULL;
+ jbi_ir_buffer = NULL;
+ }
+
+ return (JBIC_SUCCESS);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_drstop_state
+(
+ JBIE_JTAG_STATE state
+)
+
+/* */
+/****************************************************************************/
+{
+ jbi_drstop_state = state;
+
+ return (JBIC_SUCCESS);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_irstop_state
+(
+ JBIE_JTAG_STATE state
+)
+
+/* */
+/****************************************************************************/
+{
+ jbi_irstop_state = state;
+
+ return (JBIC_SUCCESS);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_dr_preamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *preamble_data
+)
+
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned int i;
+ unsigned int j;
+
+ if (jbi_workspace != NULL)
+ {
+ if (count > JBIC_MAX_JTAG_DR_PREAMBLE)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_preamble = count;
+ }
+ }
+ else
+ {
+ if (count > jbi_dr_preamble)
+ {
+ jbi_free(jbi_dr_preamble_data);
+ jbi_dr_preamble_data = (unsigned char *) jbi_malloc((count + 7) >> 3);
+
+ if (jbi_dr_preamble_data == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_preamble = count;
+ }
+ }
+ else
+ {
+ jbi_dr_preamble = count;
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ for (i = 0; i < count; ++i)
+ {
+ j = i + start_index;
+
+ if (preamble_data == NULL)
+ {
+ jbi_dr_preamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ if (preamble_data[j >> 3] & (1 << (j & 7)))
+ {
+ jbi_dr_preamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ jbi_dr_preamble_data[i >> 3] &=
+ ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_ir_preamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *preamble_data
+)
+
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned int i;
+ unsigned int j;
+
+ if (jbi_workspace != NULL)
+ {
+ if (count > JBIC_MAX_JTAG_IR_PREAMBLE)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_preamble = count;
+ }
+ }
+ else
+ {
+ if (count > jbi_ir_preamble)
+ {
+ jbi_free(jbi_ir_preamble_data);
+ jbi_ir_preamble_data = (unsigned char *) jbi_malloc((count + 7) >> 3);
+
+ if (jbi_ir_preamble_data == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_preamble = count;
+ }
+ }
+ else
+ {
+ jbi_ir_preamble = count;
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ for (i = 0; i < count; ++i)
+ {
+ j = i + start_index;
+
+ if (preamble_data == NULL)
+ {
+ jbi_ir_preamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ if (preamble_data[j >> 3] & (1 << (j & 7)))
+ {
+ jbi_ir_preamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ jbi_ir_preamble_data[i >> 3] &=
+ ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_dr_postamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *postamble_data
+)
+
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned int i;
+ unsigned int j;
+
+ if (jbi_workspace != NULL)
+ {
+ if (count > JBIC_MAX_JTAG_DR_POSTAMBLE)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_postamble = count;
+ }
+ }
+ else
+ {
+ if (count > jbi_dr_postamble)
+ {
+ jbi_free(jbi_dr_postamble_data);
+ jbi_dr_postamble_data = (unsigned char *) jbi_malloc((count + 7) >> 3);
+
+ if (jbi_dr_postamble_data == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_postamble = count;
+ }
+ }
+ else
+ {
+ jbi_dr_postamble = count;
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ for (i = 0; i < count; ++i)
+ {
+ j = i + start_index;
+
+ if (postamble_data == NULL)
+ {
+ jbi_dr_postamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ if (postamble_data[j >> 3] & (1 << (j & 7)))
+ {
+ jbi_dr_postamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ jbi_dr_postamble_data[i >> 3] &=
+ ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_set_ir_postamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *postamble_data
+)
+
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned int i;
+ unsigned int j;
+
+ if (jbi_workspace != NULL)
+ {
+ if (count > JBIC_MAX_JTAG_IR_POSTAMBLE)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_postamble = count;
+ }
+ }
+ else
+ {
+ if (count > jbi_ir_postamble)
+ {
+ jbi_free(jbi_ir_postamble_data);
+ jbi_ir_postamble_data = (unsigned char *) jbi_malloc((count + 7) >> 3);
+
+ if (jbi_ir_postamble_data == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_postamble = count;
+ }
+ }
+ else
+ {
+ jbi_ir_postamble = count;
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ for (i = 0; i < count; ++i)
+ {
+ j = i + start_index;
+
+ if (postamble_data == NULL)
+ {
+ jbi_ir_postamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ if (postamble_data[j >> 3] & (1 << (j & 7)))
+ {
+ jbi_ir_postamble_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ jbi_ir_postamble_data[i >> 3] &=
+ ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+void jbi_jtag_reset_idle(void)
+
+/* */
+/****************************************************************************/
+{
+ int i;
+
+ /*
+ * Go to Test Logic Reset (no matter what the starting state may be)
+ */
+ for (i = 0; i < 5; ++i)
+ {
+ jbi_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+ }
+
+ /*
+ * Now step to Run Test / Idle
+ */
+ jbi_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+
+ jbi_jtag_state = IDLE;
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_goto_jtag_state
+(
+ JBIE_JTAG_STATE state
+)
+
+/* */
+/****************************************************************************/
+{
+ int tms;
+ int count = 0;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+
+ if (jbi_jtag_state == JBI_ILLEGAL_JTAG_STATE)
+ {
+ /* initialize JTAG chain to known state */
+ jbi_jtag_reset_idle();
+ }
+
+ if (jbi_jtag_state == state)
+ {
+ /*
+ * We are already in the desired state. If it is a stable state,
+ * loop here. Otherwise do nothing (no clock cycles).
+ */
+ if ((state == IDLE) ||
+ (state == DRSHIFT) ||
+ (state == DRPAUSE) ||
+ (state == IRSHIFT) ||
+ (state == IRPAUSE))
+ {
+ jbi_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+ }
+ else if (state == RESET)
+ {
+ jbi_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+ }
+ }
+ else
+ {
+ while ((jbi_jtag_state != state) && (count < 9))
+ {
+ /*
+ * Get TMS value to take a step toward desired state
+ */
+ tms = (jbi_jtag_path_map[jbi_jtag_state] & (1 << state)) ?
+ TMS_HIGH : TMS_LOW;
+
+ /*
+ * Take a step
+ */
+ jbi_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+
+ if (tms)
+ {
+ jbi_jtag_state =
+ jbi_jtag_state_transitions[jbi_jtag_state].tms_high;
+ }
+ else
+ {
+ jbi_jtag_state =
+ jbi_jtag_state_transitions[jbi_jtag_state].tms_low;
+ }
+
+ ++count;
+ }
+ }
+
+ if (jbi_jtag_state != state)
+ {
+ status = JBIC_INTERNAL_ERROR;
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_do_wait_cycles
+(
+ long cycles,
+ JBIE_JTAG_STATE wait_state
+)
+
+/* */
+/* Description: Causes JTAG hardware to loop in the specified stable */
+/* state for the specified number of TCK clock cycles. */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ int tms;
+ long count;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+
+ if (jbi_jtag_state != wait_state)
+ {
+ status = jbi_goto_jtag_state(wait_state);
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Set TMS high to loop in RESET state
+ * Set TMS low to loop in any other stable state
+ */
+ tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW;
+
+ for (count = 0L; count < cycles; count++)
+ {
+ jbi_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_do_wait_microseconds
+(
+ long microseconds,
+ JBIE_JTAG_STATE wait_state
+)
+
+/* */
+/* Description: Causes JTAG hardware to sit in the specified stable */
+/* state for the specified duration of real time. If */
+/* no JTAG operations have been performed yet, then only */
+/* a delay is performed. This permits the WAIT USECS */
+/* statement to be used in VECTOR programs without causing */
+/* any JTAG operations. */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+
+ if ((jbi_jtag_state != JBI_ILLEGAL_JTAG_STATE) &&
+ (jbi_jtag_state != wait_state))
+ {
+ status = jbi_goto_jtag_state(wait_state);
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Wait for specified time interval
+ */
+ jbi_delay(microseconds);
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+void jbi_jtag_concatenate_data
+(
+ unsigned char *buffer,
+ unsigned char *preamble_data,
+ unsigned int preamble_count,
+ unsigned char *target_data,
+ unsigned long start_index,
+ unsigned int target_count,
+ unsigned char *postamble_data,
+ unsigned int postamble_count
+)
+
+/* */
+/* Description: Copies preamble data, target data, and postamble data */
+/* into one buffer for IR or DR scans. */
+/* */
+/* Returns: nothing */
+/* */
+/****************************************************************************/
+{
+ unsigned long i;
+ unsigned long j;
+ unsigned long k;
+
+ for (i = 0L; i < preamble_count; ++i)
+ {
+ if (preamble_data[i >> 3L] & (1L << (i & 7L)))
+ {
+ buffer[i >> 3L] |= (1L << (i & 7L));
+ }
+ else
+ {
+ buffer[i >> 3L] &= ~(unsigned int) (1L << (i & 7L));
+ }
+ }
+
+ j = start_index;
+ k = preamble_count + target_count;
+ for (; i < k; ++i, ++j)
+ {
+ if (target_data[j >> 3L] & (1L << (j & 7L)))
+ {
+ buffer[i >> 3L] |= (1L << (i & 7L));
+ }
+ else
+ {
+ buffer[i >> 3L] &= ~(unsigned int) (1L << (i & 7L));
+ }
+ }
+
+ j = 0L;
+ k = preamble_count + target_count + postamble_count;
+ for (; i < k; ++i, ++j)
+ {
+ if (postamble_data[j >> 3L] & (1L << (j & 7L)))
+ {
+ buffer[i >> 3L] |= (1L << (i & 7L));
+ }
+ else
+ {
+ buffer[i >> 3L] &= ~(unsigned int) (1L << (i & 7L));
+ }
+ }
+}
+
+int jbi_jtag_drscan
+(
+ int start_state,
+ int count,
+ unsigned char *tdi,
+ unsigned char *tdo
+)
+{
+ int i = 0;
+ int tdo_bit = 0;
+ int status = 1;
+
+ /*
+ * First go to DRSHIFT state
+ */
+ switch (start_state)
+ {
+ case 0: /* IDLE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(0, 0, 0); /* DRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* DRSHIFT */
+ break;
+
+ case 1: /* DRPAUSE */
+ jbi_jtag_io(1, 0, 0); /* DREXIT2 */
+ jbi_jtag_io(1, 0, 0); /* DRUPDATE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(0, 0, 0); /* DRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* DRSHIFT */
+ break;
+
+ case 2: /* IRPAUSE */
+ jbi_jtag_io(1, 0, 0); /* IREXIT2 */
+ jbi_jtag_io(1, 0, 0); /* IRUPDATE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(0, 0, 0); /* DRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* DRSHIFT */
+ break;
+
+ default:
+ status = 0;
+ }
+
+ if (status)
+ {
+ /* loop in the SHIFT-DR state */
+ for (i = 0; i < count; i++)
+ {
+ tdo_bit = jbi_jtag_io(
+ (i == count - 1),
+ tdi[i >> 3] & (1 << (i & 7)),
+ (tdo != NULL));
+
+ if (tdo != NULL)
+ {
+ if (tdo_bit)
+ {
+ tdo[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ tdo[i >> 3] &= ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+
+ jbi_jtag_io(0, 0, 0); /* DRPAUSE */
+ }
+
+ return (status);
+}
+
+int jbi_jtag_irscan
+(
+ int start_state,
+ int count,
+ unsigned char *tdi,
+ unsigned char *tdo
+)
+{
+ int i = 0;
+ int tdo_bit = 0;
+ int status = 1;
+
+ /*
+ * First go to IRSHIFT state
+ */
+ switch (start_state)
+ {
+ case 0: /* IDLE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(1, 0, 0); /* IRSELECT */
+ jbi_jtag_io(0, 0, 0); /* IRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* IRSHIFT */
+ break;
+
+ case 1: /* DRPAUSE */
+ jbi_jtag_io(1, 0, 0); /* DREXIT2 */
+ jbi_jtag_io(1, 0, 0); /* DRUPDATE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(1, 0, 0); /* IRSELECT */
+ jbi_jtag_io(0, 0, 0); /* IRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* IRSHIFT */
+ break;
+
+ case 2: /* IRPAUSE */
+ jbi_jtag_io(1, 0, 0); /* IREXIT2 */
+ jbi_jtag_io(1, 0, 0); /* IRUPDATE */
+ jbi_jtag_io(1, 0, 0); /* DRSELECT */
+ jbi_jtag_io(1, 0, 0); /* IRSELECT */
+ jbi_jtag_io(0, 0, 0); /* IRCAPTURE */
+ jbi_jtag_io(0, 0, 0); /* IRSHIFT */
+ break;
+
+ default:
+ status = 0;
+ }
+
+ if (status)
+ {
+ /* loop in the SHIFT-IR state */
+ for (i = 0; i < count; i++)
+ {
+ tdo_bit = jbi_jtag_io(
+ (i == count - 1),
+ tdi[i >> 3] & (1 << (i & 7)),
+ (tdo != NULL));
+
+ if (tdo != NULL)
+ {
+ if (tdo_bit)
+ {
+ tdo[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ tdo[i >> 3] &= ~(unsigned int) (1 << (i & 7));
+ }
+ }
+ }
+
+ jbi_jtag_io(0, 0, 0); /* IRPAUSE */
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+void jbi_jtag_extract_target_data
+(
+ unsigned char *buffer,
+ unsigned char *target_data,
+ unsigned int start_index,
+ unsigned int preamble_count,
+ unsigned int target_count
+)
+
+/* */
+/* Description: Copies target data from scan buffer, filtering out */
+/* preamble and postamble data. */
+/* */
+/* Returns: nothing */
+/* */
+/****************************************************************************/
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+
+ j = preamble_count;
+ k = start_index + target_count;
+ for (i = start_index; i < k; ++i, ++j)
+ {
+ if (buffer[j >> 3] & (1 << (j & 7)))
+ {
+ target_data[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ target_data[i >> 3] &= ~(unsigned int) (1 << (i & 7));
+ }
+ }
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_do_irscan
+(
+ unsigned int count,
+ unsigned char *tdi_data,
+ unsigned int start_index
+)
+
+/* */
+/* Description: Shifts data into instruction register */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ int start_code = 0;
+ unsigned int alloc_chars = 0;
+ unsigned int shift_count = jbi_ir_preamble + count + jbi_ir_postamble;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ JBIE_JTAG_STATE start_state = JBI_ILLEGAL_JTAG_STATE;
+
+ switch (jbi_jtag_state)
+ {
+ case JBI_ILLEGAL_JTAG_STATE:
+ case RESET:
+ case IDLE:
+ start_code = 0;
+ start_state = IDLE;
+ break;
+
+ case DRSELECT:
+ case DRCAPTURE:
+ case DRSHIFT:
+ case DREXIT1:
+ case DRPAUSE:
+ case DREXIT2:
+ case DRUPDATE:
+ start_code = 1;
+ start_state = DRPAUSE;
+ break;
+
+ case IRSELECT:
+ case IRCAPTURE:
+ case IRSHIFT:
+ case IREXIT1:
+ case IRPAUSE:
+ case IREXIT2:
+ case IRUPDATE:
+ start_code = 2;
+ start_state = IRPAUSE;
+ break;
+
+ default:
+ status = JBIC_INTERNAL_ERROR;
+ break;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_jtag_state != start_state)
+ {
+ status = jbi_goto_jtag_state(start_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_workspace != NULL)
+ {
+ if (shift_count > JBIC_MAX_JTAG_IR_LENGTH)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ }
+ else if (shift_count > jbi_ir_length)
+ {
+ alloc_chars = (shift_count + 7) >> 3;
+ jbi_free(jbi_ir_buffer);
+ jbi_ir_buffer = (unsigned char *) jbi_malloc(alloc_chars);
+
+ if (jbi_ir_buffer == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_length = alloc_chars * 8;
+ }
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Copy preamble data, IR data, and postamble data into a buffer
+ */
+ jbi_jtag_concatenate_data
+ (
+ jbi_ir_buffer,
+ jbi_ir_preamble_data,
+ jbi_ir_preamble,
+ tdi_data,
+ start_index,
+ count,
+ jbi_ir_postamble_data,
+ jbi_ir_postamble
+ );
+
+ /*
+ * Do the IRSCAN
+ */
+ jbi_jtag_irscan
+ (
+ start_code,
+ shift_count,
+ jbi_ir_buffer,
+ NULL
+ );
+
+ /* jbi_jtag_irscan() always ends in IRPAUSE state */
+ jbi_jtag_state = IRPAUSE;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_irstop_state != IRPAUSE)
+ {
+ status = jbi_goto_jtag_state(jbi_irstop_state);
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_swap_ir
+(
+ unsigned int count,
+ unsigned char *in_data,
+ unsigned int in_index,
+ unsigned char *out_data,
+ unsigned int out_index
+)
+
+/* */
+/* Description: Shifts data into instruction register, capturing output */
+/* data */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ int start_code = 0;
+ unsigned int alloc_chars = 0;
+ unsigned int shift_count = jbi_ir_preamble + count + jbi_ir_postamble;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ JBIE_JTAG_STATE start_state = JBI_ILLEGAL_JTAG_STATE;
+
+ switch (jbi_jtag_state)
+ {
+ case JBI_ILLEGAL_JTAG_STATE:
+ case RESET:
+ case IDLE:
+ start_code = 0;
+ start_state = IDLE;
+ break;
+
+ case DRSELECT:
+ case DRCAPTURE:
+ case DRSHIFT:
+ case DREXIT1:
+ case DRPAUSE:
+ case DREXIT2:
+ case DRUPDATE:
+ start_code = 1;
+ start_state = DRPAUSE;
+ break;
+
+ case IRSELECT:
+ case IRCAPTURE:
+ case IRSHIFT:
+ case IREXIT1:
+ case IRPAUSE:
+ case IREXIT2:
+ case IRUPDATE:
+ start_code = 2;
+ start_state = IRPAUSE;
+ break;
+
+ default:
+ status = JBIC_INTERNAL_ERROR;
+ break;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_jtag_state != start_state)
+ {
+ status = jbi_goto_jtag_state(start_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_workspace != NULL)
+ {
+ if (shift_count > JBIC_MAX_JTAG_IR_LENGTH)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ }
+ else if (shift_count > jbi_ir_length)
+ {
+ alloc_chars = (shift_count + 7) >> 3;
+ jbi_free(jbi_ir_buffer);
+ jbi_ir_buffer = (unsigned char *) jbi_malloc(alloc_chars);
+
+ if (jbi_ir_buffer == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_ir_length = alloc_chars * 8;
+ }
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Copy preamble data, IR data, and postamble data into a buffer
+ */
+ jbi_jtag_concatenate_data
+ (
+ jbi_ir_buffer,
+ jbi_ir_preamble_data,
+ jbi_ir_preamble,
+ in_data,
+ in_index,
+ count,
+ jbi_ir_postamble_data,
+ jbi_ir_postamble
+ );
+
+ /*
+ * Do the IRSCAN
+ */
+ jbi_jtag_irscan
+ (
+ start_code,
+ shift_count,
+ jbi_ir_buffer,
+ jbi_ir_buffer
+ );
+
+ /* jbi_jtag_irscan() always ends in IRPAUSE state */
+ jbi_jtag_state = IRPAUSE;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_irstop_state != IRPAUSE)
+ {
+ status = jbi_goto_jtag_state(jbi_irstop_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Now extract the returned data from the buffer
+ */
+ jbi_jtag_extract_target_data
+ (
+ jbi_ir_buffer,
+ out_data,
+ out_index,
+ jbi_ir_preamble,
+ count
+ );
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_do_drscan
+(
+ unsigned int count,
+ unsigned char *tdi_data,
+ unsigned long start_index
+)
+
+/* */
+/* Description: Shifts data into data register (ignoring output data) */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ int start_code = 0;
+ unsigned int alloc_chars = 0;
+ unsigned int shift_count = jbi_dr_preamble + count + jbi_dr_postamble;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ JBIE_JTAG_STATE start_state = JBI_ILLEGAL_JTAG_STATE;
+
+ switch (jbi_jtag_state)
+ {
+ case JBI_ILLEGAL_JTAG_STATE:
+ case RESET:
+ case IDLE:
+ start_code = 0;
+ start_state = IDLE;
+ break;
+
+ case DRSELECT:
+ case DRCAPTURE:
+ case DRSHIFT:
+ case DREXIT1:
+ case DRPAUSE:
+ case DREXIT2:
+ case DRUPDATE:
+ start_code = 1;
+ start_state = DRPAUSE;
+ break;
+
+ case IRSELECT:
+ case IRCAPTURE:
+ case IRSHIFT:
+ case IREXIT1:
+ case IRPAUSE:
+ case IREXIT2:
+ case IRUPDATE:
+ start_code = 2;
+ start_state = IRPAUSE;
+ break;
+
+ default:
+ status = JBIC_INTERNAL_ERROR;
+ break;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_jtag_state != start_state)
+ {
+ status = jbi_goto_jtag_state(start_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_workspace != NULL)
+ {
+ if (shift_count > JBIC_MAX_JTAG_DR_LENGTH)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ }
+ else if (shift_count > jbi_dr_length)
+ {
+ alloc_chars = (shift_count + 7) >> 3;
+ jbi_free(jbi_dr_buffer);
+ jbi_dr_buffer = (unsigned char *) jbi_malloc(alloc_chars);
+
+ if (jbi_dr_buffer == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_length = alloc_chars * 8;
+ }
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Copy preamble data, DR data, and postamble data into a buffer
+ */
+ jbi_jtag_concatenate_data
+ (
+ jbi_dr_buffer,
+ jbi_dr_preamble_data,
+ jbi_dr_preamble,
+ tdi_data,
+ start_index,
+ count,
+ jbi_dr_postamble_data,
+ jbi_dr_postamble
+ );
+
+ /*
+ * Do the DRSCAN
+ */
+ jbi_jtag_drscan
+ (
+ start_code,
+ shift_count,
+ jbi_dr_buffer,
+ NULL
+ );
+
+ /* jbi_jtag_drscan() always ends in DRPAUSE state */
+ jbi_jtag_state = DRPAUSE;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_drstop_state != DRPAUSE)
+ {
+ status = jbi_goto_jtag_state(jbi_drstop_state);
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_swap_dr
+(
+ unsigned int count,
+ unsigned char *in_data,
+ unsigned long in_index,
+ unsigned char *out_data,
+ unsigned int out_index
+)
+
+/* */
+/* Description: Shifts data into data register, capturing output data */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ int start_code = 0;
+ unsigned int alloc_chars = 0;
+ unsigned int shift_count = jbi_dr_preamble + count + jbi_dr_postamble;
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ JBIE_JTAG_STATE start_state = JBI_ILLEGAL_JTAG_STATE;
+
+ switch (jbi_jtag_state)
+ {
+ case JBI_ILLEGAL_JTAG_STATE:
+ case RESET:
+ case IDLE:
+ start_code = 0;
+ start_state = IDLE;
+ break;
+
+ case DRSELECT:
+ case DRCAPTURE:
+ case DRSHIFT:
+ case DREXIT1:
+ case DRPAUSE:
+ case DREXIT2:
+ case DRUPDATE:
+ start_code = 1;
+ start_state = DRPAUSE;
+ break;
+
+ case IRSELECT:
+ case IRCAPTURE:
+ case IRSHIFT:
+ case IREXIT1:
+ case IRPAUSE:
+ case IREXIT2:
+ case IRUPDATE:
+ start_code = 2;
+ start_state = IRPAUSE;
+ break;
+
+ default:
+ status = JBIC_INTERNAL_ERROR;
+ break;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_jtag_state != start_state)
+ {
+ status = jbi_goto_jtag_state(start_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_workspace != NULL)
+ {
+ if (shift_count > JBIC_MAX_JTAG_DR_LENGTH)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ }
+ else if (shift_count > jbi_dr_length)
+ {
+ alloc_chars = (shift_count + 7) >> 3;
+ jbi_free(jbi_dr_buffer);
+ jbi_dr_buffer = (unsigned char *) jbi_malloc(alloc_chars);
+
+ if (jbi_dr_buffer == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ jbi_dr_length = alloc_chars * 8;
+ }
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Copy preamble data, DR data, and postamble data into a buffer
+ */
+ jbi_jtag_concatenate_data
+ (
+ jbi_dr_buffer,
+ jbi_dr_preamble_data,
+ jbi_dr_preamble,
+ in_data,
+ in_index,
+ count,
+ jbi_dr_postamble_data,
+ jbi_dr_postamble
+ );
+
+ /*
+ * Do the DRSCAN
+ */
+ jbi_jtag_drscan
+ (
+ start_code,
+ shift_count,
+ jbi_dr_buffer,
+ jbi_dr_buffer
+ );
+
+ /* jbi_jtag_drscan() always ends in DRPAUSE state */
+ jbi_jtag_state = DRPAUSE;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (jbi_drstop_state != DRPAUSE)
+ {
+ status = jbi_goto_jtag_state(jbi_drstop_state);
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Now extract the returned data from the buffer
+ */
+ jbi_jtag_extract_target_data
+ (
+ jbi_dr_buffer,
+ out_data,
+ out_index,
+ jbi_dr_preamble,
+ count
+ );
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+void jbi_free_jtag_padding_buffers(int reset_jtag)
+
+/* */
+/* Description: Frees memory allocated for JTAG IR and DR buffers */
+/* */
+/* Returns: nothing */
+/* */
+/****************************************************************************/
+{
+ /*
+ * If the JTAG interface was used, reset it to TLR
+ */
+ if (reset_jtag && (jbi_jtag_state != JBI_ILLEGAL_JTAG_STATE))
+ {
+ jbi_jtag_reset_idle();
+ }
+
+ if (jbi_workspace == NULL)
+ {
+ if (jbi_dr_preamble_data != NULL)
+ {
+ jbi_free(jbi_dr_preamble_data);
+ jbi_dr_preamble_data = NULL;
+ }
+
+ if (jbi_dr_postamble_data != NULL)
+ {
+ jbi_free(jbi_dr_postamble_data);
+ jbi_dr_postamble_data = NULL;
+ }
+
+ if (jbi_dr_buffer != NULL)
+ {
+ jbi_free(jbi_dr_buffer);
+ jbi_dr_buffer = NULL;
+ }
+
+ if (jbi_ir_preamble_data != NULL)
+ {
+ jbi_free(jbi_ir_preamble_data);
+ jbi_ir_preamble_data = NULL;
+ }
+
+ if (jbi_ir_postamble_data != NULL)
+ {
+ jbi_free(jbi_ir_postamble_data);
+ jbi_ir_postamble_data = NULL;
+ }
+
+ if (jbi_ir_buffer != NULL)
+ {
+ jbi_free(jbi_ir_buffer);
+ jbi_ir_buffer = NULL;
+ }
+ }
+}
+
+#if PORT==DOS
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_do_drscan_multi_page
+(
+ unsigned int variable_id,
+ unsigned long count,
+ unsigned long start_index,
+ int version
+)
+
+/* */
+/* Description: Shifts data into data register (ignoring output data) */
+/* Scan data comes from compressed Boolean array. */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned long shift_count = jbi_dr_preamble + count + jbi_dr_postamble;
+ unsigned long i;
+ unsigned long j;
+ unsigned long k;
+ unsigned int bi;
+
+
+ if (status == JBIC_SUCCESS)
+ {
+ status = jbi_goto_jtag_state(DRSHIFT);
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ /*
+ * Get preamble data, DR data, and postamble data one bit at a time
+ * and immediately scan it into the JTAG chain
+ */
+
+ for (i = 0L; i < jbi_dr_preamble; ++i)
+ {
+ jbi_jtag_io((i == shift_count - 1),
+ (int) (jbi_dr_preamble_data[i >> 3L] & (1L << (i & 7L))), 0);
+ }
+
+ j = start_index;
+ k = jbi_dr_preamble + count;
+
+ jbi_uncompress_page(variable_id, (unsigned int) (j >> 16L), version);
+
+ for (; i < k; ++i, ++j)
+ {
+ bi = (unsigned int) (j & 0x0000ffffL);
+
+ /* check for page boundary - load next page if necessary */
+ if (bi == 0)
+ {
+ jbi_uncompress_page(variable_id, (unsigned int) (j >> 16L), version);
+ }
+
+ jbi_jtag_io((i == shift_count - 1),
+ (int) (jbi_aca_out_buffer[bi >> 3] & (1 << (bi & 7))), 0);
+ }
+
+ j = 0L;
+ k = jbi_dr_preamble + count + jbi_dr_postamble;
+ for (; i < k; ++i, ++j)
+ {
+ jbi_jtag_io((i == shift_count - 1),
+ (int) (jbi_dr_postamble_data[j >> 3L] & (1L << (j & 7L))), 0);
+ }
+
+ jbi_jtag_io(0, 0, 0); /* DRPAUSE */
+
+
+ /* jbi_jtag_drscan() always ends in DRPAUSE state */
+ jbi_jtag_state = DRPAUSE;
+
+ if (jbi_drstop_state != DRPAUSE)
+ {
+ status = jbi_goto_jtag_state(jbi_drstop_state);
+ }
+ }
+
+ return (status);
+}
+
+#endif
diff --git a/common/recipes-utils/jbi/files/code/jbijtag.h b/common/recipes-utils/jbi/files/code/jbijtag.h
new file mode 100644
index 0000000..27299f0
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbijtag.h
@@ -0,0 +1,147 @@
+/****************************************************************************/
+/* */
+/* Module: jbijtag.h */
+/* */
+/* Copyright (C) Altera Corporation 1998-2001 */
+/* */
+/* Description: Definitions of JTAG constants, types, and functions */
+/* */
+/****************************************************************************/
+
+#ifndef INC_JBIJTAG_H
+#define INC_JBIJTAG_H
+
+/****************************************************************************/
+/* */
+/* Function Prototypes */
+/* */
+/****************************************************************************/
+typedef enum
+{
+ JBI_ILLEGAL_JTAG_STATE = -1,
+ RESET = 0,
+ IDLE = 1,
+ DRSELECT = 2,
+ DRCAPTURE = 3,
+ DRSHIFT = 4,
+ DREXIT1 = 5,
+ DRPAUSE = 6,
+ DREXIT2 = 7,
+ DRUPDATE = 8,
+ IRSELECT = 9,
+ IRCAPTURE = 10,
+ IRSHIFT = 11,
+ IREXIT1 = 12,
+ IRPAUSE = 13,
+ IREXIT2 = 14,
+ IRUPDATE = 15
+
+} JBIE_JTAG_STATE;
+
+
+JBI_RETURN_TYPE jbi_init_jtag
+(
+ void
+);
+
+JBI_RETURN_TYPE jbi_set_drstop_state
+(
+ JBIE_JTAG_STATE state
+);
+
+JBI_RETURN_TYPE jbi_set_irstop_state
+(
+ JBIE_JTAG_STATE state
+);
+
+JBI_RETURN_TYPE jbi_set_dr_preamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *preamble_data
+);
+
+JBI_RETURN_TYPE jbi_set_ir_preamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *preamble_data
+);
+
+JBI_RETURN_TYPE jbi_set_dr_postamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *postamble_data
+);
+
+JBI_RETURN_TYPE jbi_set_ir_postamble
+(
+ unsigned int count,
+ unsigned int start_index,
+ unsigned char *postamble_data
+);
+
+JBI_RETURN_TYPE jbi_goto_jtag_state
+(
+ JBIE_JTAG_STATE state
+);
+
+JBI_RETURN_TYPE jbi_do_wait_cycles
+(
+ long cycles,
+ JBIE_JTAG_STATE wait_state
+);
+
+JBI_RETURN_TYPE jbi_do_wait_microseconds
+(
+ long microseconds,
+ JBIE_JTAG_STATE wait_state
+);
+
+JBI_RETURN_TYPE jbi_do_irscan
+(
+ unsigned int count,
+ unsigned char *tdi_data,
+ unsigned int start_index
+);
+
+JBI_RETURN_TYPE jbi_swap_ir
+(
+ unsigned int count,
+ unsigned char *in_data,
+ unsigned int in_index,
+ unsigned char *out_data,
+ unsigned int out_index
+);
+
+JBI_RETURN_TYPE jbi_do_drscan
+(
+ unsigned int count,
+ unsigned char *tdi_data,
+ unsigned long start_index
+);
+
+JBI_RETURN_TYPE jbi_swap_dr
+(
+ unsigned int count,
+ unsigned char *in_data,
+ unsigned long in_index,
+ unsigned char *out_data,
+ unsigned int out_index
+);
+
+void jbi_free_jtag_padding_buffers
+(
+ int reset_jtag
+);
+
+JBI_RETURN_TYPE jbi_do_drscan_multi_page
+(
+ unsigned int variable_id,
+ unsigned long long_count,
+ unsigned long long_index,
+ int version
+);
+
+#endif /* INC_JBIJTAG_H */
diff --git a/common/recipes-utils/jbi/files/code/jbimain.c b/common/recipes-utils/jbi/files/code/jbimain.c
new file mode 100644
index 0000000..79bdf69
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbimain.c
@@ -0,0 +1,3290 @@
+/****************************************************************************/
+/* */
+/* Module: jbimain.c */
+/* */
+/* Copyright (C) Altera Corporation 1998-2001 */
+/* */
+/* Description: Jam STAPL ByteCode Player (Interpreter) */
+/* */
+/* Revisions: 2.2 fixed /W4 warnings */
+/* 2.0 added support for STAPL ByteCode format */
+/* */
+/****************************************************************************/
+
+#include "jbiport.h"
+#include "jbiexprt.h"
+#include "jbijtag.h"
+#include "jbicomp.h"
+
+/****************************************************************************/
+/* */
+/* MACROS */
+/* */
+/****************************************************************************/
+
+#define NULL 0
+
+#define JBI_STACK_SIZE 128
+
+#define JBIC_MESSAGE_LENGTH 1024
+
+/*
+* This macro checks if enough parameters are available on the stack. The
+* argument is the number of parameters needed.
+*/
+#define IF_CHECK_STACK(x) \
+ if (stack_ptr < (int) (x)) \
+ { \
+ status = JBIC_STACK_OVERFLOW; \
+ } \
+ else
+
+/*
+* This macro checks if a code address is inside the code section
+*/
+#define CHECK_PC \
+ if ((pc < code_section) || (pc >= debug_section)) \
+ { \
+ status = JBIC_BOUNDS_ERROR; \
+ }
+
+/****************************************************************************/
+/* */
+/* GLOBAL VARIABLES */
+/* */
+/****************************************************************************/
+
+#if PORT==DOS
+/*
+* jbi_program is a global pointer used by macros GET_BYTE, GET_WORD, and
+* GET_DWORD to read data from the JBC file
+*/
+PROGRAM_PTR jbi_program;
+#endif
+
+/****************************************************************************/
+/* */
+/* UTILITY FUNCTIONS */
+/* */
+/****************************************************************************/
+
+int jbi_strlen(char *string)
+{
+ int len = 0;
+
+ while (string[len] != '\0') ++len;
+
+ return (len);
+}
+
+long jbi_atol(char *buffer)
+{
+ long result = 0L;
+ int index = 0;
+
+ while ((buffer[index] >= '0') && (buffer[index] <= '9'))
+ {
+ result = (result * 10) + (buffer[index] - '0');
+ ++index;
+ }
+
+ return (result);
+}
+
+void jbi_ltoa(char *buffer, long number)
+{
+ int index = 0;
+ int rev_index = 0;
+ char reverse[32];
+
+ if (number < 0L)
+ {
+ buffer[index++] = '-';
+ number = 0 - number;
+ }
+ else if (number == 0)
+ {
+ buffer[index++] = '0';
+ }
+
+ while (number != 0)
+ {
+ reverse[rev_index++] = (char) ((number % 10) + '0');
+ number /= 10;
+ }
+
+ while (rev_index > 0)
+ {
+ buffer[index++] = reverse[--rev_index];
+ }
+
+ buffer[index] = '\0';
+}
+
+char jbi_toupper(char ch)
+{
+ return ((char) (((ch >= 'a') && (ch <= 'z')) ? (ch + 'A' - 'a') : ch));
+}
+
+int jbi_stricmp(char *left, char *right)
+{
+ int result = 0;
+ char l, r;
+
+ do
+ {
+ l = jbi_toupper(*left);
+ r = jbi_toupper(*right);
+ result = l - r;
+ ++left;
+ ++right;
+ }
+ while ((result == 0) && (l != '\0') && (r != '\0'));
+
+ return (result);
+}
+
+void jbi_strncpy(char *left, char *right, int count)
+{
+ char ch;
+
+ do
+ {
+ *left = *right;
+ ch = *right;
+ ++left;
+ ++right;
+ --count;
+ }
+ while ((ch != '\0') && (count != 0));
+}
+
+void jbi_make_dword(unsigned char *buf, unsigned long num)
+{
+ buf[0] = (unsigned char) num;
+ buf[1] = (unsigned char) (num >> 8L);
+ buf[2] = (unsigned char) (num >> 16L);
+ buf[3] = (unsigned char) (num >> 24L);
+}
+
+unsigned long jbi_get_dword(unsigned char *buf)
+{
+ return
+ (((unsigned long) buf[0]) |
+ (((unsigned long) buf[1]) << 8L) |
+ (((unsigned long) buf[2]) << 16L) |
+ (((unsigned long) buf[3]) << 24L));
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_execute
+(
+ PROGRAM_PTR program,
+ long program_size,
+ char *workspace,
+ long workspace_size,
+ char *action,
+ char **init_list,
+ int reset_jtag,
+ long *error_address,
+ int *exit_code,
+ int *format_version
+)
+
+/* */
+/* Description: */
+/* */
+/* Returns: */
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned long first_word = 0L;
+ unsigned long action_table = 0L;
+ unsigned long proc_table = 0L;
+ unsigned long string_table = 0L;
+ unsigned long symbol_table = 0L;
+ unsigned long data_section = 0L;
+ unsigned long code_section = 0L;
+ unsigned long debug_section = 0L;
+ unsigned long action_count = 0L;
+ unsigned long proc_count = 0L;
+ unsigned long symbol_count = 0L;
+ char message_buffer[JBIC_MESSAGE_LENGTH + 1];
+ long *variables = NULL;
+ long *variable_size = NULL;
+ char *attributes = NULL;
+ unsigned char *proc_attributes = NULL;
+ unsigned long pc;
+ unsigned long opcode_address;
+ unsigned long args[3];
+ unsigned int opcode;
+ unsigned long name_id;
+ long stack[JBI_STACK_SIZE] = {0};
+ unsigned char charbuf[4];
+ long long_temp;
+ unsigned int variable_id;
+ unsigned char *charptr_temp;
+ unsigned char *charptr_temp2;
+ long *longptr_temp;
+ int version = 0;
+ int delta = 0;
+ int stack_ptr = 0;
+ unsigned int arg_count;
+ int done = 0;
+ int bad_opcode = 0;
+ unsigned int count;
+ unsigned int index;
+ unsigned int index2;
+ long long_count;
+ long long_index;
+ long long_index2;
+ unsigned int i;
+ unsigned int j;
+ unsigned long uncompressed_size;
+ unsigned int offset;
+ unsigned long value;
+ int current_proc = 0;
+ char *equal_ptr;
+ int length;
+ int reverse;
+
+#if PORT==DOS
+ char name[33];
+#else
+ char *name;
+#endif
+
+ jbi_workspace = workspace;
+ jbi_workspace_size = workspace_size;
+
+#if PORT==DOS
+ jbi_program = program;
+#endif
+
+ /*
+ * Read header information
+ */
+ if (program_size > 52L)
+ {
+ first_word = GET_DWORD(0);
+ version = (int) (first_word & 1L);
+ *format_version = version + 1;
+ delta = version * 8;
+
+ action_table = GET_DWORD(4);
+ proc_table = GET_DWORD(8);
+ string_table = GET_DWORD(4 + delta);
+ symbol_table = GET_DWORD(16 + delta);
+ data_section = GET_DWORD(20 + delta);
+ code_section = GET_DWORD(24 + delta);
+ debug_section = GET_DWORD(28 + delta);
+ action_count = GET_DWORD(40 + delta);
+ proc_count = GET_DWORD(44 + delta);
+ symbol_count = GET_DWORD(48 + (2 * delta));
+ }
+
+ if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+ {
+ done = 1;
+ status = JBIC_IO_ERROR;
+ }
+
+ if ((status == JBIC_SUCCESS) && (symbol_count > 0))
+ {
+ variables = (long *) jbi_malloc(
+ (unsigned int) symbol_count * sizeof(long));
+
+ if (variables == NULL) status = JBIC_OUT_OF_MEMORY;
+
+ if (status == JBIC_SUCCESS)
+ {
+ variable_size = (long *) jbi_malloc(
+ (unsigned int) symbol_count * sizeof(long));
+
+ if (variable_size == NULL) status = JBIC_OUT_OF_MEMORY;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ attributes = (char *) jbi_malloc((unsigned int) symbol_count);
+
+ if (attributes == NULL) status = JBIC_OUT_OF_MEMORY;
+ }
+
+ if ((status == JBIC_SUCCESS) && (version > 0))
+ {
+ proc_attributes = (unsigned char *) jbi_malloc((unsigned int) proc_count);
+
+ if (proc_attributes == NULL) status = JBIC_OUT_OF_MEMORY;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ delta = version * 2;
+
+ for (i = 0; i < (unsigned int) symbol_count; ++i)
+ {
+ offset = (unsigned int) (symbol_table + ((11 + delta) * i));
+
+ value = GET_DWORD(offset + 3 + delta);
+
+ attributes[i] = GET_BYTE(offset);
+
+ /* use bit 7 of attribute byte to indicate that this buffer */
+ /* was dynamically allocated and should be freed later */
+ attributes[i] &= 0x7f;
+
+ variable_size[i] = GET_DWORD(offset + 7 + delta);
+
+ /*
+ * Attribute bits:
+ * bit 0: 0 = read-only, 1 = read-write
+ * bit 1: 0 = not compressed, 1 = compressed
+ * bit 2: 0 = not initialized, 1 = initialized
+ * bit 3: 0 = scalar, 1 = array
+ * bit 4: 0 = Boolean, 1 = integer
+ * bit 5: 0 = declared variable,
+ * 1 = compiler created temporary variable
+ */
+
+ if ((attributes[i] & 0x0c) == 0x04)
+ {
+ /* initialized scalar variable */
+ variables[i] = value;
+ }
+ else if ((attributes[i] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+#if PORT==DOS
+ /* for DOS port, get the size but do not uncompress */
+ long_index = data_section + value;
+ uncompressed_size =
+ (((unsigned long) GET_BYTE(long_index)) |
+ (((unsigned long) GET_BYTE(long_index + 1L)) << 8L) |
+ (((unsigned long) GET_BYTE(long_index + 2L)) << 16L) |
+ (((unsigned long) GET_BYTE(long_index + 3L)) << 24L));
+ variable_size[i] = uncompressed_size;
+#else
+ uncompressed_size = jbi_get_dword(
+ &program[data_section + value]);
+
+ /* allocate a buffer for the uncompressed data */
+ variables[i] = (long) jbi_malloc(uncompressed_size);
+
+ if (variables[i] == 0L)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ /* set flag so buffer will be freed later */
+ attributes[i] |= 0x80;
+
+ /* uncompress the data */
+ if (jbi_uncompress(
+ &program[data_section + value],
+ variable_size[i],
+ (unsigned char *) variables[i],
+ uncompressed_size,
+ version)
+ != uncompressed_size)
+ {
+ /* decompression failed */
+ status = JBIC_IO_ERROR;
+ }
+ else
+ {
+ variable_size[i] = uncompressed_size * 8L;
+ }
+ }
+#endif
+ }
+ else if ((attributes[i] & 0x1e) == 0x0c)
+ {
+ /* initialized Boolean array */
+#if PORT==DOS
+ /* flag attributes so that memory is freed */
+ attributes[i] |= 0x80;
+
+ if (variable_size[i] > 0)
+ {
+ unsigned int size = (unsigned int)
+ ((variable_size[i] + 7L) / 8L);
+
+ variables[i] = (long) jbi_malloc(size);
+
+ if (variables[i] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ unsigned char *p = (unsigned char *) variables[i];
+ /* copy array values into buffer */
+ for (j = 0; j < size; ++j)
+ {
+ p[j] = GET_BYTE(data_section + value + j);
+ }
+ }
+ }
+ else
+ {
+ variables[i] = 0;
+ }
+#else
+ variables[i] = value + data_section + (long) program;
+#endif
+ }
+ else if ((attributes[i] & 0x1c) == 0x1c)
+ {
+ /* initialized integer array */
+ variables[i] = value + data_section;
+ }
+ else if ((attributes[i] & 0x0c) == 0x08)
+ {
+ /* uninitialized array */
+
+ /* flag attributes so that memory is freed */
+ attributes[i] |= 0x80;
+
+ if (variable_size[i] > 0)
+ {
+ unsigned int size;
+
+ if (attributes[i] & 0x10)
+ {
+ /* integer array */
+ size = (unsigned int)
+ (variable_size[i] * sizeof(long));
+ }
+ else
+ {
+ /* Boolean array */
+ size = (unsigned int)
+ ((variable_size[i] + 7L) / 8L);
+ }
+
+ variables[i] = (long) jbi_malloc(size);
+
+ if (variables[i] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ /* zero out memory */
+ for (j = 0; j < size; ++j)
+ {
+ ((unsigned char *)(variables[i]))[j] = 0;
+ }
+ }
+ }
+ else
+ {
+ variables[i] = 0;
+ }
+ }
+ else
+ {
+ variables[i] = 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * Initialize variables listed in init_list
+ */
+ if ((status == JBIC_SUCCESS) && (init_list != NULL) && (version == 0))
+ {
+ delta = version * 2;
+ count = 0;
+ while (init_list[count] != NULL)
+ {
+ equal_ptr = init_list[count];
+ length = 0;
+ while ((*equal_ptr != '=') && (*equal_ptr != '\0'))
+ {
+ ++equal_ptr;
+ ++length;
+ }
+ if (*equal_ptr == '=')
+ {
+ ++equal_ptr;
+ value = jbi_atol(equal_ptr);
+ jbi_strncpy(message_buffer, init_list[count], length);
+ message_buffer[length] = '\0';
+ for (i = 0; i < (unsigned int) symbol_count; ++i)
+ {
+ offset = (unsigned int) (symbol_table + ((11 + delta) * i));
+ name_id = (version == 0) ? GET_WORD(offset + 1) :
+ GET_DWORD(offset + 1);
+#if PORT==DOS
+ for (j = 0; j < 32; ++j)
+ {
+ name[j] = GET_BYTE(string_table + name_id + j);
+ }
+ name[32] = '\0';
+#else
+ name = (char *) &program[string_table + name_id];
+#endif
+
+ if (jbi_stricmp(message_buffer, name) == 0)
+ {
+ variables[i] = value;
+ }
+ }
+ }
+
+ ++count;
+ }
+ }
+
+ if (status != JBIC_SUCCESS) done = 1;
+
+ jbi_init_jtag();
+
+ pc = code_section;
+ message_buffer[0] = '\0';
+
+ /*
+ * For JBC version 2, we will execute the procedures corresponding to
+ * the selected ACTION
+ */
+ if (version > 0)
+ {
+ if (action == NULL)
+ {
+ status = JBIC_ACTION_NOT_FOUND;
+ done = 1;
+ }
+ else
+ {
+ int action_found = 0;
+
+ for (i = 0; (i < action_count) && !action_found; ++i)
+ {
+ name_id = GET_DWORD(action_table + (12 * i));
+
+#if PORT==DOS
+ for (j = 0; j < 32; ++j)
+ {
+ name[j] = GET_BYTE(string_table + name_id + j);
+ }
+ name[32] = '\0';
+#else
+ name = (char *) &program[string_table + name_id];
+#endif
+
+ if (jbi_stricmp(action, name) == 0)
+ {
+ action_found = 1;
+ current_proc = (int) GET_DWORD(action_table + (12 * i) + 8);
+ }
+ }
+
+ if (!action_found)
+ {
+ status = JBIC_ACTION_NOT_FOUND;
+ done = 1;
+ }
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ int first_time = 1;
+ i = current_proc;
+ while ((i != 0) || first_time)
+ {
+ first_time = 0;
+ /* check procedure attribute byte */
+ proc_attributes[i] = (unsigned char)
+ (GET_BYTE(proc_table + (13 * i) + 8) & 0x03);
+
+ if (proc_attributes[i] != 0)
+ {
+ /*
+ * BIT0 - OPTIONAL
+ * BIT1 - RECOMMENDED
+ * BIT6 - FORCED OFF
+ * BIT7 - FORCED ON
+ */
+ if (init_list != NULL)
+ {
+ name_id = GET_DWORD(proc_table + (13 * i));
+#if PORT==DOS
+ for (j = 0; j < 32; ++j)
+ {
+ name[j] = GET_BYTE(string_table + name_id + j);
+ }
+ name[32] = '\0';
+#else
+ name = (char *) &program[string_table + name_id];
+#endif
+ count = 0;
+ while (init_list[count] != NULL)
+ {
+ equal_ptr = init_list[count];
+ length = 0;
+ while ((*equal_ptr != '=') && (*equal_ptr != '\0'))
+ {
+ ++equal_ptr;
+ ++length;
+ }
+ if (*equal_ptr == '=')
+ {
+ ++equal_ptr;
+ jbi_strncpy(message_buffer, init_list[count], length);
+ message_buffer[length] = '\0';
+
+ if (jbi_stricmp(message_buffer, name) == 0)
+ {
+ if (jbi_atol(equal_ptr) == 0)
+ {
+ proc_attributes[i] |= 0x40;
+ }
+ else
+ {
+ proc_attributes[i] |= 0x80;
+ }
+ }
+ }
+
+ ++count;
+ }
+ }
+ }
+
+ i = (unsigned int) GET_DWORD(proc_table + (13 * i) + 4);
+ }
+
+ /*
+ * Set current_proc to the first procedure to be executed
+ */
+ i = current_proc;
+ while ((i != 0) &&
+ ((proc_attributes[i] == 1) ||
+ ((proc_attributes[i] & 0xc0) == 0x40)))
+ {
+ i = (unsigned int) GET_DWORD(proc_table + (13 * i) + 4);
+ }
+
+ if ((i != 0) || ((i == 0) && (current_proc == 0) &&
+ ((proc_attributes[0] != 1) &&
+ ((proc_attributes[0] & 0xc0) != 0x40))))
+ {
+ current_proc = i;
+ pc = code_section + GET_DWORD(proc_table + (13 * i) + 9);
+ CHECK_PC;
+ }
+ else
+ {
+ /* there are no procedures to execute! */
+ done = 1;
+ }
+ }
+ }
+
+ message_buffer[0] = '\0';
+
+ while (!done)
+ {
+ opcode = (unsigned int) (GET_BYTE(pc) & 0xff);
+ opcode_address = pc;
+ ++pc;
+
+ arg_count = (opcode >> 6) & 3;
+ for (i = 0; i < arg_count; ++i)
+ {
+ args[i] = GET_DWORD(pc);
+ pc += 4;
+ }
+
+ switch (opcode)
+ {
+ case 0x00: /* NOP */
+ /* do nothing */
+ break;
+
+ case 0x01: /* DUP */
+ IF_CHECK_STACK(1)
+ {
+ stack[stack_ptr] = stack[stack_ptr - 1];
+ ++stack_ptr;
+ }
+ break;
+
+ case 0x02: /* SWP */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[stack_ptr - 2];
+ stack[stack_ptr - 2] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+ break;
+
+ case 0x03: /* ADD */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] += stack[stack_ptr];
+ }
+ break;
+
+ case 0x04: /* SUB */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] -= stack[stack_ptr];
+ }
+ break;
+
+ case 0x05: /* MULT */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] *= stack[stack_ptr];
+ }
+ break;
+
+ case 0x06: /* DIV */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] /= stack[stack_ptr];
+ }
+ break;
+
+ case 0x07: /* MOD */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] %= stack[stack_ptr];
+ }
+ break;
+
+ case 0x08: /* SHL */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] <<= stack[stack_ptr];
+ }
+ break;
+
+ case 0x09: /* SHR */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] >>= stack[stack_ptr];
+ }
+ break;
+
+ case 0x0A: /* NOT */
+ IF_CHECK_STACK(1)
+ {
+ stack[stack_ptr - 1] ^= (-1L);
+ }
+ break;
+
+ case 0x0B: /* AND */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] &= stack[stack_ptr];
+ }
+ break;
+
+ case 0x0C: /* OR */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] |= stack[stack_ptr];
+ }
+ break;
+
+ case 0x0D: /* XOR */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] ^= stack[stack_ptr];
+ }
+ break;
+
+ case 0x0E: /* INV */
+ IF_CHECK_STACK(1)
+ {
+ stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L;
+ }
+ break;
+
+ case 0x0F: /* GT */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] =
+ (stack[stack_ptr - 1] > stack[stack_ptr]) ? 1L : 0L;
+ }
+ break;
+
+ case 0x10: /* LT */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] =
+ (stack[stack_ptr - 1] < stack[stack_ptr]) ? 1L : 0L;
+ }
+ break;
+
+ case 0x11: /* RET */
+ if ((version > 0) && (stack_ptr == 0))
+ {
+ /*
+ * We completed one of the main procedures of an ACTION.
+ * Find the next procedure to be executed and jump to it.
+ * If there are no more procedures, then EXIT.
+ */
+ i = (unsigned int) GET_DWORD(proc_table + (13 * current_proc) + 4);
+ while ((i != 0) &&
+ ((proc_attributes[i] == 1) ||
+ ((proc_attributes[i] & 0xc0) == 0x40)))
+ {
+ i = (unsigned int) GET_DWORD(proc_table + (13 * i) + 4);
+ }
+
+ if (i == 0)
+ {
+ /* there are no procedures to execute! */
+ done = 1;
+ *exit_code = 0; /* success */
+ }
+ else
+ {
+ current_proc = i;
+ pc = code_section + GET_DWORD(proc_table + (13 * i) + 9);
+ CHECK_PC;
+ }
+ }
+ else IF_CHECK_STACK(1)
+ {
+ pc = stack[--stack_ptr] + code_section;
+ CHECK_PC;
+ if (pc == code_section)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ }
+ break;
+
+ case 0x12: /* CMPS */
+ /*
+ * Array short compare
+ * ...stack 0 is source 1 value
+ * ...stack 1 is source 2 value
+ * ...stack 2 is mask value
+ * ...stack 3 is count
+ */
+ IF_CHECK_STACK(4)
+ {
+ long a = stack[--stack_ptr];
+ long b = stack[--stack_ptr];
+ long_temp = stack[--stack_ptr];
+ count = (unsigned int) stack[stack_ptr - 1];
+
+ if ((count < 1) || (count > 32))
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ long_temp &= ((-1L) >> (32 - count));
+
+ stack[stack_ptr - 1] =
+ ((a & long_temp) == (b & long_temp)) ? 1L : 0L;
+ }
+ }
+ break;
+
+ case 0x13: /* PINT */
+ /*
+ * PRINT add integer
+ * ...stack 0 is integer value
+ */
+ IF_CHECK_STACK(1)
+ {
+ jbi_ltoa(&message_buffer[jbi_strlen(message_buffer)],
+ stack[--stack_ptr]);
+ }
+ break;
+
+ case 0x14: /* PRNT */
+ /*
+ * PRINT finish
+ */
+ jbi_message(message_buffer);
+ message_buffer[0] = '\0';
+ break;
+
+ case 0x15: /* DSS */
+ /*
+ * DRSCAN short
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_do_drscan(count, charbuf, 0);
+ }
+ break;
+
+ case 0x16: /* DSSC */
+ /*
+ * DRSCAN short with capture
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[--stack_ptr];
+ count = (unsigned int) stack[stack_ptr - 1];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_swap_dr(count, charbuf, 0, charbuf, 0);
+ stack[stack_ptr - 1] = jbi_get_dword(charbuf);
+ }
+ break;
+
+ case 0x17: /* ISS */
+ /*
+ * IRSCAN short
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_do_irscan(count, charbuf, 0);
+ }
+ break;
+
+ case 0x18: /* ISSC */
+ /*
+ * IRSCAN short with capture
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[--stack_ptr];
+ count = (unsigned int) stack[stack_ptr - 1];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_swap_ir(count, charbuf, 0, charbuf, 0);
+ stack[stack_ptr - 1] = jbi_get_dword(charbuf);
+ }
+ break;
+
+ case 0x19: /* VSS */
+ /*
+ * VECTOR short
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x1A: /* VSSC */
+ /*
+ * VECTOR short with capture
+ * ...stack 0 is scan data
+ * ...stack 1 is count
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x1B: /* VMPF */
+ /*
+ * VMAP finish
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x1C: /* DPR */
+ IF_CHECK_STACK(1)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ status = jbi_set_dr_preamble(count, 0, NULL);
+ }
+ break;
+
+ case 0x1D: /* DPRL */
+ /*
+ * DRPRE with literal data
+ * ...stack 0 is count
+ * ...stack 1 is literal data
+ */
+ IF_CHECK_STACK(2)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ long_temp = stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_set_dr_preamble(count, 0, charbuf);
+ }
+ break;
+
+ case 0x1E: /* DPO */
+ /*
+ * DRPOST
+ * ...stack 0 is count
+ */
+ IF_CHECK_STACK(1)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ status = jbi_set_dr_postamble(count, 0, NULL);
+ }
+ break;
+
+ case 0x1F: /* DPOL */
+ /*
+ * DRPOST with literal data
+ * ...stack 0 is count
+ * ...stack 1 is literal data
+ */
+ IF_CHECK_STACK(2)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ long_temp = stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_set_dr_postamble(count, 0, charbuf);
+ }
+ break;
+
+ case 0x20: /* IPR */
+ IF_CHECK_STACK(1)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ status = jbi_set_ir_preamble(count, 0, NULL);
+ }
+ break;
+
+ case 0x21: /* IPRL */
+ /*
+ * IRPRE with literal data
+ * ...stack 0 is count
+ * ...stack 1 is literal data
+ */
+ IF_CHECK_STACK(2)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ long_temp = stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_set_ir_preamble(count, 0, charbuf);
+ }
+ break;
+
+ case 0x22: /* IPO */
+ /*
+ * IRPOST
+ * ...stack 0 is count
+ */
+ IF_CHECK_STACK(1)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ status = jbi_set_ir_postamble(count, 0, NULL);
+ }
+ break;
+
+ case 0x23: /* IPOL */
+ /*
+ * IRPOST with literal data
+ * ...stack 0 is count
+ * ...stack 1 is literal data
+ */
+ IF_CHECK_STACK(2)
+ {
+ count = (unsigned int) stack[--stack_ptr];
+ long_temp = stack[--stack_ptr];
+ jbi_make_dword(charbuf, long_temp);
+ status = jbi_set_ir_postamble(count, 0, charbuf);
+ }
+ break;
+
+ case 0x24: /* PCHR */
+ IF_CHECK_STACK(1)
+ {
+ unsigned char ch;
+ count = jbi_strlen(message_buffer);
+ ch = (char) stack[--stack_ptr];
+ if ((ch < 1) || (ch > 127))
+ {
+ /* character code out of range */
+ /* instead of flagging an error, force the value to 127 */
+ ch = 127;
+ }
+ message_buffer[count] = ch;
+ message_buffer[count + 1] = '\0';
+ }
+ break;
+
+ case 0x25: /* EXIT */
+ IF_CHECK_STACK(1)
+ {
+ *exit_code = (int) stack[--stack_ptr];
+ }
+ done = 1;
+ break;
+
+ case 0x26: /* EQU */
+ IF_CHECK_STACK(2)
+ {
+ --stack_ptr;
+ stack[stack_ptr - 1] =
+ (stack[stack_ptr - 1] == stack[stack_ptr]) ? 1L : 0L;
+ }
+ break;
+
+ case 0x27: /* POPT */
+ IF_CHECK_STACK(1)
+ {
+ --stack_ptr;
+ }
+ break;
+
+ case 0x28: /* TRST */
+ bad_opcode = 1;
+ break;
+
+ case 0x29: /* FRQ */
+ bad_opcode = 1;
+ break;
+
+ case 0x2A: /* FRQU */
+ bad_opcode = 1;
+ break;
+
+ case 0x2B: /* PD32 */
+ bad_opcode = 1;
+ break;
+
+ case 0x2C: /* ABS */
+ IF_CHECK_STACK(1)
+ {
+ if (stack[stack_ptr - 1] < 0)
+ {
+ stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1];
+ }
+ }
+ break;
+
+ case 0x2D: /* BCH0 */
+ /*
+ * Batch operation 0
+ * SWP
+ * SWPN 7
+ * SWP
+ * SWPN 6
+ * DUPN 8
+ * SWPN 2
+ * SWP
+ * DUPN 6
+ * DUPN 6
+ */
+
+ /* SWP */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[stack_ptr - 2];
+ stack[stack_ptr - 2] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* SWPN 7 */
+ index = 7 + 1;
+ IF_CHECK_STACK(index)
+ {
+ long_temp = stack[stack_ptr - index];
+ stack[stack_ptr - index] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* SWP */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[stack_ptr - 2];
+ stack[stack_ptr - 2] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* SWPN 6 */
+ index = 6 + 1;
+ IF_CHECK_STACK(index)
+ {
+ long_temp = stack[stack_ptr - index];
+ stack[stack_ptr - index] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* DUPN 8 */
+ index = 8 + 1;
+ IF_CHECK_STACK(index)
+ {
+ stack[stack_ptr] = stack[stack_ptr - index];
+ ++stack_ptr;
+ }
+
+ /* SWPN 2 */
+ index = 2 + 1;
+ IF_CHECK_STACK(index)
+ {
+ long_temp = stack[stack_ptr - index];
+ stack[stack_ptr - index] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* SWP */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[stack_ptr - 2];
+ stack[stack_ptr - 2] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+
+ /* DUPN 6 */
+ index = 6 + 1;
+ IF_CHECK_STACK(index)
+ {
+ stack[stack_ptr] = stack[stack_ptr - index];
+ ++stack_ptr;
+ }
+
+ /* DUPN 6 */
+ index = 6 + 1;
+ IF_CHECK_STACK(index)
+ {
+ stack[stack_ptr] = stack[stack_ptr - index];
+ ++stack_ptr;
+ }
+ break;
+
+ case 0x2E: /* BCH1 */
+ /*
+ * Batch operation 1
+ * SWPN 8
+ * SWP
+ * SWPN 9
+ * SWPN 3
+ * SWP
+ * SWPN 2
+ * SWP
+ * SWPN 7
+ * SWP
+ * SWPN 6
+ * DUPN 5
+ * DUPN 5
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x2F: /* PSH0 */
+ stack[stack_ptr++] = 0;
+ break;
+
+ case 0x40: /* PSHL */
+ stack[stack_ptr++] = (long) args[0];
+ break;
+
+ case 0x41: /* PSHV */
+ stack[stack_ptr++] = variables[args[0]];
+ break;
+
+ case 0x42: /* JMP */
+ pc = args[0] + code_section;
+ CHECK_PC;
+ break;
+
+ case 0x43: /* CALL */
+ stack[stack_ptr++] = pc;
+ pc = args[0] + code_section;
+ CHECK_PC;
+ break;
+
+ case 0x44: /* NEXT */
+ /*
+ * Process FOR / NEXT loop
+ * ...argument 0 is variable ID
+ * ...stack 0 is step value
+ * ...stack 1 is end value
+ * ...stack 2 is top address
+ */
+ IF_CHECK_STACK(3)
+ {
+ long step = stack[stack_ptr - 1];
+ long end = stack[stack_ptr - 2];
+ long top = stack[stack_ptr - 3];
+ long iterator = variables[args[0]];
+ int break_out = 0;
+
+ if (step < 0)
+ {
+ if (iterator <= end) break_out = 1;
+ }
+ else
+ {
+ if (iterator >= end) break_out = 1;
+ }
+
+ if (break_out)
+ {
+ stack_ptr -= 3;
+ }
+ else
+ {
+ variables[args[0]] = iterator + step;
+ pc = top + code_section;
+ CHECK_PC;
+ }
+ }
+ break;
+
+ case 0x45: /* PSTR */
+ /*
+ * PRINT add string
+ * ...argument 0 is string ID
+ */
+#if PORT==DOS
+ long_index = string_table + args[0];
+ index2 = jbi_strlen(message_buffer);
+
+ do
+ {
+ i = GET_BYTE(long_index);
+ message_buffer[index2] = (char) i;
+ ++long_index;
+ ++index2;
+ }
+ while ((i != '\0') && (index2 < JBIC_MESSAGE_LENGTH));
+#else
+ count = jbi_strlen(message_buffer);
+ jbi_strncpy(&message_buffer[count],
+ (char *) &program[string_table + args[0]],
+ JBIC_MESSAGE_LENGTH - count);
+#endif
+ message_buffer[JBIC_MESSAGE_LENGTH] = '\0';
+ break;
+
+ case 0x46: /* VMAP */
+ /*
+ * VMAP add signal name
+ * ...argument 0 is string ID
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x47: /* SINT */
+ /*
+ * STATE intermediate state
+ * ...argument 0 is state code
+ */
+ status = jbi_goto_jtag_state((int) args[0]);
+ break;
+
+ case 0x48: /* ST */
+ /*
+ * STATE final state
+ * ...argument 0 is state code
+ */
+ status = jbi_goto_jtag_state((int) args[0]);
+ break;
+
+ case 0x49: /* ISTP */
+ /*
+ * IRSTOP state
+ * ...argument 0 is state code
+ */
+ status = jbi_set_irstop_state((int) args[0]);
+ break;
+
+ case 0x4A: /* DSTP */
+ /*
+ * DRSTOP state
+ * ...argument 0 is state code
+ */
+ status = jbi_set_drstop_state((int) args[0]);
+ break;
+
+ case 0x4B: /* SWPN */
+ /*
+ * Exchange top with Nth stack value
+ * ...argument 0 is 0-based stack entry to swap with top element
+ */
+ index = ((int) args[0]) + 1;
+ IF_CHECK_STACK(index)
+ {
+ long_temp = stack[stack_ptr - index];
+ stack[stack_ptr - index] = stack[stack_ptr - 1];
+ stack[stack_ptr - 1] = long_temp;
+ }
+ break;
+
+ case 0x4C: /* DUPN */
+ /*
+ * Duplicate Nth stack value
+ * ...argument 0 is 0-based stack entry to duplicate
+ */
+ index = ((int) args[0]) + 1;
+ IF_CHECK_STACK(index)
+ {
+ stack[stack_ptr] = stack[stack_ptr - index];
+ ++stack_ptr;
+ }
+ break;
+
+ case 0x4D: /* POPV */
+ /*
+ * Pop stack into scalar variable
+ * ...argument 0 is variable ID
+ * ...stack 0 is value
+ */
+ IF_CHECK_STACK(1)
+ {
+ variables[args[0]] = stack[--stack_ptr];
+ }
+ break;
+
+ case 0x4E: /* POPE */
+ /*
+ * Pop stack into integer array element
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is value
+ */
+ IF_CHECK_STACK(2)
+ {
+ variable_id = (unsigned int) args[0];
+
+ /*
+ * If variable is read-only, convert to writable array
+ */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x1c))
+ {
+ /*
+ * Allocate a writable buffer for this array
+ */
+ count = (unsigned int) variable_size[variable_id];
+ long_temp = variables[variable_id];
+ longptr_temp = (long *) jbi_malloc(count * sizeof(long));
+ variables[variable_id] = (long) longptr_temp;
+
+ if (variables[variable_id] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ /* copy previous contents into buffer */
+ for (i = 0; i < count; ++i)
+ {
+ longptr_temp[i] = GET_DWORD(long_temp);
+ long_temp += 4L;
+ }
+
+ /* set bit 7 - buffer was dynamically allocated */
+ attributes[variable_id] |= 0x80;
+
+ /* clear bit 2 - variable is writable */
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+ }
+
+#if PORT==DOS
+ /* for 16-bit version, allow writing in allocated buffers */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x9c))
+ {
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+#endif
+
+ /* check that variable is a writable integer array */
+ if ((attributes[variable_id] & 0x1c) != 0x18)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ longptr_temp = (long *) variables[variable_id];
+
+ /* pop the array index */
+ index = (unsigned int) stack[--stack_ptr];
+
+ /* pop the value and store it into the array */
+ longptr_temp[index] = stack[--stack_ptr];
+ }
+ }
+ break;
+
+ case 0x4F: /* POPA */
+ /*
+ * Pop stack into Boolean array
+ * ...argument 0 is variable ID
+ * ...stack 0 is count
+ * ...stack 1 is array index
+ * ...stack 2 is value
+ */
+ IF_CHECK_STACK(3)
+ {
+ variable_id = (unsigned int) args[0];
+
+ /*
+ * If variable is read-only, convert to writable array
+ */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x0c))
+ {
+ /*
+ * Allocate a writable buffer for this array
+ */
+ long_temp = (variable_size[variable_id] + 7L) >> 3L;
+ charptr_temp2 = (unsigned char *) variables[variable_id];
+ charptr_temp = jbi_malloc((unsigned int) long_temp);
+ variables[variable_id] = (long) charptr_temp;
+
+ if (variables[variable_id] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ /* zero the buffer */
+ for (long_index = 0L;
+ long_index < long_temp;
+ ++long_index)
+ {
+ charptr_temp[long_index] = 0;
+ }
+
+ /* copy previous contents into buffer */
+ for (long_index = 0L;
+ long_index < variable_size[variable_id];
+ ++long_index)
+ {
+#if PORT==DOS
+ if ((attributes[variable_id] & 0x02) &&
+ ((long_index & 0x0000FFFF) == 0L))
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (long_index >> 16), version);
+ charptr_temp = jbi_aca_out_buffer;
+ long_index2 = long_index & 0xFFFF;
+ }
+#else
+ long_index2 = long_index;
+#endif
+
+ if (charptr_temp2[long_index2 >> 3] &
+ (1 << (long_index2 & 7)))
+ {
+ charptr_temp[long_index >> 3] |=
+ (1 << (long_index & 7));
+ }
+ }
+
+ /* set bit 7 - buffer was dynamically allocated */
+ attributes[variable_id] |= 0x80;
+
+ /* clear bit 2 - variable is writable */
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+ }
+
+#if PORT==DOS
+ /* for 16-bit version, allow writing in allocated buffers */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x8c))
+ {
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+#endif
+
+ /* check that variable is a writable Boolean array */
+ if ((attributes[variable_id] & 0x1c) != 0x08)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ charptr_temp = (unsigned char *) variables[variable_id];
+
+ /* pop the count (number of bits to copy) */
+ long_count = stack[--stack_ptr];
+
+ /* pop the array index */
+ long_index = stack[--stack_ptr];
+
+ reverse = 0;
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+
+ if (long_index > long_count)
+ {
+ reverse = 1;
+ long_temp = long_count;
+ long_count = 1 + long_index - long_count;
+ long_index = long_temp;
+
+ /* reverse POPA is not supported */
+ status = JBIC_BOUNDS_ERROR;
+ break;
+ }
+ else
+ {
+ long_count = 1 + long_count - long_index;
+ }
+ }
+
+ /* pop the data */
+ long_temp = stack[--stack_ptr];
+
+ if (long_count < 1)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ for (i = 0; i < (unsigned int) long_count; ++i)
+ {
+ if (long_temp & (1L << (long) i))
+ {
+ charptr_temp[long_index >> 3L] |=
+ (1L << (long_index & 7L));
+ }
+ else
+ {
+ charptr_temp[long_index >> 3L] &=
+ ~ (unsigned int) (1L << (long_index & 7L));
+ }
+ ++long_index;
+ }
+ }
+ }
+ }
+ break;
+
+ case 0x50: /* JMPZ */
+ /*
+ * Pop stack and branch if zero
+ * ...argument 0 is address
+ * ...stack 0 is condition value
+ */
+ IF_CHECK_STACK(1)
+ {
+ if (stack[--stack_ptr] == 0)
+ {
+ pc = args[0] + code_section;
+ CHECK_PC;
+ }
+ }
+ break;
+
+ case 0x51: /* DS */
+ case 0x52: /* IS */
+ /*
+ * DRSCAN
+ * IRSCAN
+ * ...argument 0 is scan data variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_index = stack[--stack_ptr];
+ long_count = stack[--stack_ptr];
+
+ reverse = 0;
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ /* stack 2 = count */
+ long_temp = long_count;
+ long_count = stack[--stack_ptr];
+
+ if (long_index > long_temp)
+ {
+ reverse = 1;
+ long_index = long_temp;
+ }
+ }
+
+#if PORT==DOS
+ if (((long_index & 0xFFFF0000) == 0) &&
+ ((long_count & 0xFFFF0000) == 0))
+ {
+ variable_id = (unsigned int) args[0];
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (long_index >> 16), version);
+ long_index &= 0x0000ffff;
+ charptr_temp = jbi_aca_out_buffer;
+ }
+ else
+ {
+ charptr_temp = (unsigned char *) variables[variable_id];
+ }
+
+ if (reverse)
+ {
+ /* allocate a buffer and reverse the data order */
+ charptr_temp2 = charptr_temp;
+ charptr_temp = jbi_malloc((unsigned int)
+ ((long_count >> 3L) + 1L));
+
+ if (charptr_temp == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ long_temp = long_index + long_count - 1;
+ long_index2 = 0;
+ while (long_index2 < long_count)
+ {
+ if (charptr_temp2[long_temp >> 3] &
+ (1 << (long_temp & 7)))
+ {
+ charptr_temp[long_index2 >> 3] |=
+ (1 << (long_index2 & 7));
+ }
+ else
+ {
+ charptr_temp[long_index2 >> 3] &=
+ ~(1 << (long_index2 & 7));
+ }
+
+ --long_temp;
+ ++long_index2;
+ }
+ }
+ }
+
+ if (opcode == 0x51) /* DS */
+ {
+ status = jbi_do_drscan((unsigned int) long_count,
+ charptr_temp, (unsigned long) long_index);
+ }
+ else /* IS */
+ {
+ status = jbi_do_irscan((unsigned int) long_count,
+ charptr_temp, (unsigned int) long_index);
+ }
+
+ if (reverse) jbi_free(charptr_temp);
+ }
+ else if ((opcode == 0x51) && !reverse)
+ {
+ status = jbi_do_drscan_multi_page(
+ (unsigned int) args[0],
+ (unsigned long) long_count,
+ (unsigned long) long_index, version);
+ }
+ else
+ {
+ /* reverse multi-page scans are not supported */
+ /* multi-page IR scans are not supported */
+ status = JBIC_BOUNDS_ERROR;
+ }
+#else
+ charptr_temp = (unsigned char *) variables[args[0]];
+
+ if (reverse)
+ {
+ /* allocate a buffer and reverse the data order */
+ charptr_temp2 = charptr_temp;
+ charptr_temp = jbi_malloc((long_count >> 3) + 1);
+ if (charptr_temp == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ long_temp = long_index + long_count - 1;
+ long_index2 = 0;
+ while (long_index2 < long_count)
+ {
+ if (charptr_temp2[long_temp >> 3] &
+ (1 << (long_temp & 7)))
+ {
+ charptr_temp[long_index2 >> 3] |=
+ (1 << (long_index2 & 7));
+ }
+ else
+ {
+ charptr_temp[long_index2 >> 3] &=
+ ~(1 << (long_index2 & 7));
+ }
+
+ --long_temp;
+ ++long_index2;
+ }
+ }
+ }
+
+ if (opcode == 0x51) /* DS */
+ {
+ status = jbi_do_drscan((unsigned int) long_count,
+ charptr_temp, (unsigned long) long_index);
+ }
+ else /* IS */
+ {
+ status = jbi_do_irscan((unsigned int) long_count,
+ charptr_temp, (unsigned int) long_index);
+ }
+#endif
+
+ if (reverse && (charptr_temp != NULL))
+ {
+ jbi_free(charptr_temp);
+ }
+ }
+ break;
+
+ case 0x53: /* DPRA */
+ /*
+ * DRPRE with array data
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ index = (unsigned int) stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ count = 1 + count - index;
+ }
+
+ charptr_temp = (unsigned char *) variables[args[0]];
+ status = jbi_set_dr_preamble(count, index, charptr_temp);
+ }
+ break;
+
+ case 0x54: /* DPOA */
+ /*
+ * DRPOST with array data
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ index = (unsigned int) stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ count = 1 + count - index;
+ }
+
+ charptr_temp = (unsigned char *) variables[args[0]];
+ status = jbi_set_dr_postamble(count, index, charptr_temp);
+ }
+ break;
+
+ case 0x55: /* IPRA */
+ /*
+ * IRPRE with array data
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ index = (unsigned int) stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ count = 1 + count - index;
+ }
+
+ charptr_temp = (unsigned char *) variables[args[0]];
+ status = jbi_set_ir_preamble(count, index, charptr_temp);
+ }
+ break;
+
+ case 0x56: /* IPOA */
+ /*
+ * IRPOST with array data
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ * ...stack 1 is count
+ */
+ IF_CHECK_STACK(2)
+ {
+ index = (unsigned int) stack[--stack_ptr];
+ count = (unsigned int) stack[--stack_ptr];
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ count = 1 + count - index;
+ }
+
+ charptr_temp = (unsigned char *) variables[args[0]];
+ status = jbi_set_ir_postamble(count, index, charptr_temp);
+ }
+ break;
+
+ case 0x57: /* EXPT */
+ /*
+ * EXPORT
+ * ...argument 0 is string ID
+ * ...stack 0 is integer expression
+ */
+ IF_CHECK_STACK(1)
+ {
+#if PORT==DOS
+ name_id = args[0];
+ for (j = 0; j < 32; ++j)
+ {
+ name[j] = GET_BYTE(string_table + name_id + j);
+ }
+ name[32] = '\0';
+#else
+ name = (char *) &program[string_table + args[0]];
+#endif
+ long_temp = stack[--stack_ptr];
+ jbi_export_integer(name, long_temp);
+ }
+ break;
+
+ case 0x58: /* PSHE */
+ /*
+ * Push integer array element
+ * ...argument 0 is variable ID
+ * ...stack 0 is array index
+ */
+ IF_CHECK_STACK(1)
+ {
+ variable_id = (unsigned int) args[0];
+ index = (unsigned int) stack[stack_ptr - 1];
+
+ /* check variable type */
+ if ((attributes[variable_id] & 0x1f) == 0x19)
+ {
+ /* writable integer array */
+ longptr_temp = (long *) variables[variable_id];
+ stack[stack_ptr - 1] = longptr_temp[index];
+ }
+ else if ((attributes[variable_id] & 0x1f) == 0x1c)
+ {
+ /* read-only integer array */
+ long_temp = variables[variable_id] + (4L * index);
+ stack[stack_ptr - 1] = GET_DWORD(long_temp);
+ }
+ else
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ }
+ break;
+
+ case 0x59: /* PSHA */
+ /*
+ * Push Boolean array
+ * ...argument 0 is variable ID
+ * ...stack 0 is count
+ * ...stack 1 is array index
+ */
+ IF_CHECK_STACK(2)
+ {
+ variable_id = (unsigned int) args[0];
+
+ /* check that variable is a Boolean array */
+ if ((attributes[variable_id] & 0x18) != 0x08)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ charptr_temp = (unsigned char *) variables[variable_id];
+
+ /* pop the count (number of bits to copy) */
+ count = (unsigned int) stack[--stack_ptr];
+
+ /* pop the array index */
+ index = (unsigned int) stack[stack_ptr - 1];
+
+ if (version > 0)
+ {
+ /* stack 0 = array right index */
+ /* stack 1 = array left index */
+ count = 1 + count - index;
+ }
+
+ if ((count < 1) || (count > 32))
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+#if PORT==DOS
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (stack[stack_ptr - 1] >> 16), version);
+ charptr_temp = jbi_aca_out_buffer;
+ }
+#endif
+ long_temp = 0L;
+
+ for (i = 0; i < count; ++i)
+ {
+ if (charptr_temp[(i + index) >> 3] &
+ (1 << ((i + index) & 7)))
+ {
+ long_temp |= (1L << i);
+ }
+ }
+
+ stack[stack_ptr - 1] = long_temp;
+ }
+ }
+ }
+ break;
+
+ case 0x5A: /* DYNA */
+ /*
+ * Dynamically change size of array
+ * ...argument 0 is variable ID
+ * ...stack 0 is new size
+ */
+ IF_CHECK_STACK(1)
+ {
+ variable_id = (unsigned int) args[0];
+ long_temp = stack[--stack_ptr];
+
+ if (long_temp > variable_size[variable_id])
+ {
+ variable_size[variable_id] = long_temp;
+
+ if (attributes[variable_id] & 0x10)
+ {
+ /* allocate integer array */
+ long_temp *= 4;
+ }
+ else
+ {
+ /* allocate Boolean array */
+ long_temp = (long_temp + 7) >> 3;
+ }
+
+ /*
+ * If the buffer was previously allocated, free it
+ */
+ if ((attributes[variable_id] & 0x80) &&
+ (variables[variable_id] != NULL))
+ {
+ jbi_free((void *) variables[variable_id]);
+ variables[variable_id] = NULL;
+ }
+
+ /*
+ * Allocate a new buffer of the requested size
+ */
+ variables[variable_id] = (long)
+ jbi_malloc((unsigned int) long_temp);
+
+ if (variables[variable_id] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ /*
+ * Set the attribute bit to indicate that this buffer
+ * was dynamically allocated and should be freed later
+ */
+ attributes[variable_id] |= 0x80;
+
+ /* zero out memory */
+ count = (unsigned int)
+ ((variable_size[variable_id] + 7L) / 8L);
+ charptr_temp = (unsigned char *)
+ (variables[variable_id]);
+ for (index = 0; index < count; ++index)
+ {
+ charptr_temp[index] = 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case 0x5B: /* EXPR */
+ bad_opcode = 1;
+ break;
+
+ case 0x5C: /* EXPV */
+ /*
+ * Export Boolean array
+ * ...argument 0 is string ID
+ * ...stack 0 is variable ID
+ * ...stack 1 is array right index
+ * ...stack 2 is array left index
+ */
+ IF_CHECK_STACK(3)
+ {
+ if (version == 0)
+ {
+ /* EXPV is not supported in JBC 1.0 */
+ bad_opcode = 1;
+ break;
+ }
+#if PORT==DOS
+ name_id = args[0];
+ for (j = 0; j < 32; ++j)
+ {
+ name[j] = GET_BYTE(string_table + name_id + j);
+ }
+ name[32] = '\0';
+#else
+ name = (char *) &program[string_table + args[0]];
+#endif
+ variable_id = (unsigned int) stack[--stack_ptr];
+ long_index = stack[--stack_ptr]; /* right index */
+ long_index2 = stack[--stack_ptr]; /* left index */
+
+ if (long_index > long_index2)
+ {
+ /* reverse indices not supported */
+ status = JBIC_BOUNDS_ERROR;
+ break;
+ }
+
+ long_count = 1 + long_index2 - long_index;
+
+ charptr_temp = (unsigned char *) variables[variable_id];
+ charptr_temp2 = NULL;
+
+#if PORT==DOS
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (long_index >> 16), version);
+ charptr_temp = jbi_aca_out_buffer;
+ long_index &= 0x0000FFFF;
+ }
+#endif
+
+ if ((long_index & 7L) != 0)
+ {
+ charptr_temp2 = jbi_malloc((unsigned int)
+ ((long_count + 7L) / 8L));
+ if (charptr_temp2 == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ long k = long_index;
+ for (i = 0; i < (unsigned int) long_count; ++i)
+ {
+ if (charptr_temp[k >> 3] & (1 << (k & 7)))
+ {
+ charptr_temp2[i >> 3] |= (1 << (i & 7));
+ }
+ else
+ {
+ charptr_temp2[i >> 3] &= ~(1 << (i & 7));
+ }
+
+ ++k;
+ }
+ charptr_temp = charptr_temp2;
+ }
+ }
+ else if (long_index != 0)
+ {
+ charptr_temp = &charptr_temp[long_index >> 3];
+ }
+
+ jbi_export_boolean_array(name, charptr_temp, long_count);
+
+ /* free allocated buffer */
+ if (((long_index & 7L) != 0) && (charptr_temp2 != NULL))
+ {
+ jbi_free(charptr_temp2);
+ }
+ }
+ break;
+
+ case 0x80: /* COPY */
+ /*
+ * Array copy
+ * ...argument 0 is dest ID
+ * ...argument 1 is source ID
+ * ...stack 0 is count
+ * ...stack 1 is dest index
+ * ...stack 2 is source index
+ */
+ IF_CHECK_STACK(3)
+ {
+ long copy_count = stack[--stack_ptr];
+ long copy_index = stack[--stack_ptr];
+ long copy_index2 = stack[--stack_ptr];
+ long destleft;
+ long src_count;
+ long dest_count;
+ int src_reverse = 0;
+ int dest_reverse = 0;
+
+ reverse = 0;
+
+ if (version > 0)
+ {
+ /* stack 0 = source right index */
+ /* stack 1 = source left index */
+ /* stack 2 = destination right index */
+ /* stack 3 = destination left index */
+ destleft = stack[--stack_ptr];
+
+ if (copy_count > copy_index)
+ {
+ src_reverse = 1;
+ reverse = 1;
+ src_count = 1 + copy_count - copy_index;
+ /* copy_index = source start index */
+ }
+ else
+ {
+ src_count = 1 + copy_index - copy_count;
+ copy_index = copy_count; /* source start index */
+ }
+
+ if (copy_index2 > destleft)
+ {
+ dest_reverse = 1;
+ reverse = !reverse;
+ dest_count = 1 + copy_index2 - destleft;
+ copy_index2 = destleft; /* destination start index */
+ }
+ else
+ {
+ dest_count = 1 + destleft - copy_index2;
+ /* copy_index2 = destination start index */
+ }
+
+ copy_count = (src_count < dest_count) ? src_count : dest_count;
+
+ if ((src_reverse || dest_reverse) &&
+ (src_count != dest_count))
+ {
+ /* If either the source or destination is reversed, */
+ /* we can't tolerate a length mismatch, because we */
+ /* "left justify" the arrays when copying. This */
+ /* won't work correctly with reversed arrays. */
+ status = JBIC_BOUNDS_ERROR;
+ }
+ }
+
+ count = (unsigned int) copy_count;
+ index = (unsigned int) copy_index;
+ index2 = (unsigned int) copy_index2;
+
+ /*
+ * If destination is a read-only array, allocate a buffer
+ * and convert it to a writable array
+ */
+ variable_id = (unsigned int) args[1];
+ if ((version > 0) && ((attributes[variable_id] & 0x9c) == 0x0c))
+ {
+ /*
+ * Allocate a writable buffer for this array
+ */
+ long_temp = (variable_size[variable_id] + 7L) >> 3L;
+ charptr_temp2 = (unsigned char *) variables[variable_id];
+ charptr_temp = jbi_malloc((unsigned int) long_temp);
+ variables[variable_id] = (long) charptr_temp;
+
+ if (variables[variable_id] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ /* zero the buffer */
+ for (long_index = 0L;
+ long_index < long_temp;
+ ++long_index)
+ {
+ charptr_temp[long_index] = 0;
+ }
+
+ /* copy previous contents into buffer */
+ for (long_index = 0L;
+ long_index < variable_size[variable_id];
+ ++long_index)
+ {
+#if PORT==DOS
+ if ((attributes[variable_id] & 0x02) &&
+ ((long_index & 0x0000FFFF) == 0L))
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (long_index >> 16), version);
+ charptr_temp = jbi_aca_out_buffer;
+ long_index2 = long_index & 0xFFFF;
+ }
+#else
+ long_index2 = long_index;
+#endif
+
+ if (charptr_temp2[long_index2 >> 3] &
+ (1 << (long_index2 & 7)))
+ {
+ charptr_temp[long_index >> 3] |=
+ (1 << (long_index & 7));
+ }
+ }
+
+ /* set bit 7 - buffer was dynamically allocated */
+ attributes[variable_id] |= 0x80;
+
+ /* clear bit 2 - variable is writable */
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+ }
+
+#if PORT==DOS
+ /* for 16-bit version, allow writing in allocated buffers */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x8c))
+ {
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+#endif
+
+ charptr_temp = (unsigned char *) variables[args[1]];
+ charptr_temp2 = (unsigned char *) variables[args[0]];
+
+#if PORT==DOS
+ variable_id = (unsigned int) args[0];
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (copy_index >> 16), version);
+ charptr_temp2 = jbi_aca_out_buffer;
+ }
+#endif
+
+ /* check that destination is a writable Boolean array */
+ if ((attributes[args[1]] & 0x1c) != 0x08)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ break;
+ }
+
+ if (count < 1)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+ if (reverse)
+ {
+ index2 += (count - 1);
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ if (charptr_temp2[index >> 3] & (1 << (index & 7)))
+ {
+ charptr_temp[index2 >> 3] |= (1 << (index2 & 7));
+ }
+ else
+ {
+ charptr_temp[index2 >> 3] &=
+ ~(unsigned int) (1 << (index2 & 7));
+ }
+ ++index;
+ if (reverse) --index2; else ++index2;
+ }
+ }
+ }
+ break;
+
+ case 0x81: /* REVA */
+ /*
+ * ARRAY COPY reversing bit order
+ * ...argument 0 is dest ID
+ * ...argument 1 is source ID
+ * ...stack 0 is dest index
+ * ...stack 1 is source index
+ * ...stack 2 is count
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0x82: /* DSC */
+ case 0x83: /* ISC */
+ /*
+ * DRSCAN with capture
+ * IRSCAN with capture
+ * ...argument 0 is scan data variable ID
+ * ...argument 1 is capture variable ID
+ * ...stack 0 is capture index
+ * ...stack 1 is scan data index
+ * ...stack 2 is count
+ */
+ IF_CHECK_STACK(3)
+ {
+ long scan_right, scan_left;
+ long capture_count = 0;
+ long scan_count = 0;
+ long capture_index = stack[--stack_ptr];
+ long scan_index = stack[--stack_ptr];
+ if (version > 0)
+ {
+ /* stack 0 = capture right index */
+ /* stack 1 = capture left index */
+ /* stack 2 = scan right index */
+ /* stack 3 = scan left index */
+ /* stack 4 = count */
+ scan_right = stack[--stack_ptr];
+ scan_left = stack[--stack_ptr];
+ capture_count = 1 + scan_index - capture_index;
+ scan_count = 1 + scan_left - scan_right;
+ scan_index = scan_right;
+ }
+ long_count = stack[--stack_ptr];
+
+ /*
+ * If capture array is read-only, allocate a buffer
+ * and convert it to a writable array
+ */
+ variable_id = (unsigned int) args[1];
+ if ((version > 0) && ((attributes[variable_id] & 0x9c) == 0x0c))
+ {
+ /*
+ * Allocate a writable buffer for this array
+ */
+ long_temp = (variable_size[variable_id] + 7L) >> 3L;
+ charptr_temp2 = (unsigned char *) variables[variable_id];
+ charptr_temp = jbi_malloc((unsigned int) long_temp);
+ variables[variable_id] = (long) charptr_temp;
+
+ if (variables[variable_id] == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ break;
+ }
+ else
+ {
+ /* zero the buffer */
+ for (long_index = 0L;
+ long_index < long_temp;
+ ++long_index)
+ {
+ charptr_temp[long_index] = 0;
+ }
+
+ /* copy previous contents into buffer */
+ for (long_index = 0L;
+ long_index < variable_size[variable_id];
+ ++long_index)
+ {
+#if PORT==DOS
+ if ((attributes[variable_id] & 0x02) &&
+ ((long_index & 0x0000FFFF) == 0L))
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (long_index >> 16), version);
+ charptr_temp = jbi_aca_out_buffer;
+ long_index2 = long_index & 0xFFFF;
+ }
+#else
+ long_index2 = long_index;
+#endif
+
+ if (charptr_temp2[long_index2 >> 3] &
+ (1 << (long_index2 & 7)))
+ {
+ charptr_temp[long_index >> 3] |=
+ (1 << (long_index & 7));
+ }
+ }
+
+ /* set bit 7 - buffer was dynamically allocated */
+ attributes[variable_id] |= 0x80;
+
+ /* clear bit 2 - variable is writable */
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+ }
+
+#if PORT==DOS
+ /* for 16-bit version, allow writing in allocated buffers */
+ if ((version > 0) &&
+ ((attributes[variable_id] & 0x9c) == 0x8c))
+ {
+ attributes[variable_id] &= ~0x04;
+ attributes[variable_id] |= 0x01;
+ }
+#endif
+
+ charptr_temp = (unsigned char *) variables[args[0]];
+ charptr_temp2 = (unsigned char *) variables[args[1]];
+
+#if PORT==DOS
+ variable_id = (unsigned int) args[0];
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ /* initialized compressed Boolean array */
+ jbi_uncompress_page(variable_id,
+ (int) (scan_index >> 16), version);
+ scan_index &= 0x0000ffff;
+ charptr_temp = jbi_aca_out_buffer;
+ }
+#endif
+
+ if ((version > 0) &&
+ ((long_count > capture_count) || (long_count > scan_count)))
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+
+ /* check that capture array is a writable Boolean array */
+ if ((attributes[args[1]] & 0x1c) != 0x08)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ if (opcode == 0x82) /* DSC */
+ {
+ status = jbi_swap_dr((unsigned int) long_count,
+ charptr_temp, (unsigned long) scan_index,
+ charptr_temp2, (unsigned int) capture_index);
+ }
+ else /* ISC */
+ {
+ status = jbi_swap_ir((unsigned int) long_count,
+ charptr_temp, (unsigned int) scan_index,
+ charptr_temp2, (unsigned int) capture_index);
+ }
+ }
+ }
+ break;
+
+ case 0x84: /* WAIT */
+ /*
+ * WAIT
+ * ...argument 0 is wait state
+ * ...argument 1 is end state
+ * ...stack 0 is cycles
+ * ...stack 1 is microseconds
+ */
+ IF_CHECK_STACK(2)
+ {
+ long_temp = stack[--stack_ptr];
+
+ if (long_temp != 0L)
+ {
+ status = jbi_do_wait_cycles(long_temp, (unsigned int) args[0]);
+ }
+
+ long_temp = stack[--stack_ptr];
+
+ if ((status == JBIC_SUCCESS) && (long_temp != 0L))
+ {
+ status = jbi_do_wait_microseconds(long_temp, (unsigned int) args[0]);
+ }
+
+ if ((status == JBIC_SUCCESS) && (args[1] != args[0]))
+ {
+ status = jbi_goto_jtag_state((unsigned int) args[1]);
+ }
+
+ if (version > 0)
+ {
+ --stack_ptr; /* throw away MAX cycles */
+ --stack_ptr; /* throw away MAX microseconds */
+ }
+ }
+ break;
+
+ case 0x85: /* VS */
+ /*
+ * VECTOR
+ * ...argument 0 is dir data variable ID
+ * ...argument 1 is scan data variable ID
+ * ...stack 0 is dir array index
+ * ...stack 1 is scan array index
+ * ...stack 2 is count
+ */
+ bad_opcode = 1;
+ break;
+
+ case 0xC0: /* CMPA */
+ /*
+ * Array compare
+ * ...argument 0 is source 1 ID
+ * ...argument 1 is source 2 ID
+ * ...argument 2 is mask ID
+ * ...stack 0 is source 1 index
+ * ...stack 1 is source 2 index
+ * ...stack 2 is mask index
+ * ...stack 3 is count
+ */
+ IF_CHECK_STACK(4)
+ {
+ long a, b;
+ unsigned char *source1 = (unsigned char *) variables[args[0]];
+ unsigned char *source2 = (unsigned char *) variables[args[1]];
+ unsigned char *mask = (unsigned char *) variables[args[2]];
+ unsigned long index1 = stack[--stack_ptr];
+ unsigned long index2 = stack[--stack_ptr];
+ unsigned long mask_index = stack[--stack_ptr];
+ long_count = stack[--stack_ptr];
+
+ if (version > 0)
+ {
+ /* stack 0 = source 1 right index */
+ /* stack 1 = source 1 left index */
+ /* stack 2 = source 2 right index */
+ /* stack 3 = source 2 left index */
+ /* stack 4 = mask right index */
+ /* stack 5 = mask left index */
+ long mask_right = stack[--stack_ptr];
+ long mask_left = stack[--stack_ptr];
+ a = 1 + index2 - index1; /* source 1 count */
+ b = 1 + long_count - mask_index; /* source 2 count */
+ a = (a < b) ? a : b;
+ b = 1 + mask_left - mask_right; /* mask count */
+ a = (a < b) ? a : b;
+ index2 = mask_index; /* source 2 start index */
+ mask_index = mask_right; /* mask start index */
+ long_count = a;
+ }
+
+ long_temp = 1L;
+
+ if (long_count < 1)
+ {
+ status = JBIC_BOUNDS_ERROR;
+ }
+ else
+ {
+#if PORT==DOS
+ variable_id = (unsigned int) args[0];
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ jbi_uncompress_page(variable_id,
+ (int) (index1 >> 16), version);
+ index1 &= 0x0000ffff;
+ source1 = jbi_aca_out_buffer;
+ }
+
+ variable_id = (unsigned int) args[1];
+ if ((attributes[variable_id] & 0x1e) == 0x0e)
+ {
+ jbi_uncompress_page(variable_id,
+ (int) (index2 >> 16), version);
+ index2 &= 0x0000ffff;
+ source2 = jbi_aca_out_buffer;
+ }
+#endif
+ count = (unsigned int) long_count;
+
+ for (i = 0; i < count; ++i)
+ {
+ if (mask[mask_index >> 3] & (1 << (mask_index & 7)))
+ {
+ a = source1[index1 >> 3] & (1 << (index1 & 7))
+ ? 1 : 0;
+ b = source2[index2 >> 3] & (1 << (index2 & 7))
+ ? 1 : 0;
+
+ if (a != b) long_temp = 0L; /* failure */
+ }
+ ++index1;
+ ++index2;
+ ++mask_index;
+ }
+ }
+
+ stack[stack_ptr++] = long_temp;
+ }
+ break;
+
+ case 0xC1: /* VSC */
+ /*
+ * VECTOR with capture
+ * ...argument 0 is dir data variable ID
+ * ...argument 1 is scan data variable ID
+ * ...argument 2 is capture variable ID
+ * ...stack 0 is capture index
+ * ...stack 1 is scan data index
+ * ...stack 2 is dir data index
+ * ...stack 3 is count
+ */
+ bad_opcode = 1;
+ break;
+
+ default:
+ /*
+ * Unrecognized opcode -- ERROR!
+ */
+ bad_opcode = 1;
+ break;
+ }
+
+ if (bad_opcode)
+ {
+ status = JBIC_ILLEGAL_OPCODE;
+ }
+
+ if ((stack_ptr < 0) || (stack_ptr >= JBI_STACK_SIZE))
+ {
+ status = JBIC_STACK_OVERFLOW;
+ }
+
+ if (status != JBIC_SUCCESS)
+ {
+ done = 1;
+ *error_address = (long) (opcode_address - code_section);
+ }
+ }
+
+ jbi_free_jtag_padding_buffers(reset_jtag);
+
+ /*
+ * Free all dynamically allocated arrays
+ */
+ if ((attributes != NULL) && (variables != NULL))
+ {
+ for (i = 0; i < (unsigned int) symbol_count; ++i)
+ {
+ if ((attributes[i] & 0x80) && (variables[i] != NULL))
+ {
+ jbi_free((void *) variables[i]);
+ }
+ }
+ }
+
+ if (variables != NULL) jbi_free(variables);
+
+ if (variable_size != NULL) jbi_free(variable_size);
+
+ if (attributes != NULL) jbi_free(attributes);
+
+ if (proc_attributes != NULL) jbi_free(proc_attributes);
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_get_note
+(
+ PROGRAM_PTR program,
+ long program_size,
+ long *offset,
+ char *key,
+ char *value,
+ int length
+)
+
+/* */
+/* Description: Gets key and value of NOTE fields in the JBC file. */
+/* Can be called in two modes: if offset pointer is NULL, */
+/* then the function searches for note fields which match */
+/* the key string provided. If offset is not NULL, then */
+/* the function finds the next note field of any key, */
+/* starting at the offset specified by the offset pointer. */
+/* */
+/* Returns: JBIC_SUCCESS for success, else appropriate error code */
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_UNEXPECTED_END;
+ unsigned long note_strings = 0L;
+ unsigned long note_table = 0L;
+ unsigned long note_count = 0L;
+ unsigned long first_word = 0L;
+ int version = 0;
+ int delta = 0;
+ char *key_ptr;
+ char *value_ptr;
+ int i;
+
+#if PORT==DOS
+ int count = 0;
+ int done = 0;
+ long long_index = 0;
+ char key_buffer[256];
+ char value_buffer[256];
+
+ jbi_program = program;
+#endif
+
+ /*
+ * Read header information
+ */
+ if (program_size > 52L)
+ {
+ first_word = GET_DWORD(0);
+ version = (int) (first_word & 1L);
+ delta = version * 8;
+
+ note_strings = GET_DWORD(8 + delta);
+ note_table = GET_DWORD(12 + delta);
+ note_count = GET_DWORD(44 + (2 * delta));
+ }
+
+ if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+ {
+ status = JBIC_IO_ERROR;
+ }
+ else if (note_count > 0L)
+ {
+ if (offset == NULL)
+ {
+ /*
+ * We will search for the first note with a specific key, and
+ * return only the value
+ */
+ for (i = 0; (i < (int) note_count) && (status != JBIC_SUCCESS); ++i)
+ {
+#if PORT==DOS
+ done = 0;
+ count = 0;
+ long_index = note_strings + GET_DWORD(note_table + (8 * i));
+ while ((count < 255) && !done)
+ {
+ key_buffer[count] = GET_BYTE(long_index);
+ if (key_buffer[count] == '\0') done = 1;
+ ++long_index;
+ ++count;
+ }
+ key_buffer[255] = '\0';
+ key_ptr = key_buffer;
+#else
+ key_ptr = (char *) &program[note_strings +
+ GET_DWORD(note_table + (8 * i))];
+#endif
+ if ((key != NULL) && (jbi_stricmp(key, key_ptr) == 0))
+ {
+ status = JBIC_SUCCESS;
+
+#if PORT==DOS
+ done = 0;
+ count = 0;
+ long_index = note_strings + GET_DWORD(note_table + (8 * i) + 4);
+ while ((count < 255) && !done)
+ {
+ value_buffer[count] = GET_BYTE(long_index);
+ if (value_buffer[count] == '\0') done = 1;
+ ++long_index;
+ ++count;
+ }
+ value_buffer[255] = '\0';
+ value_ptr = value_buffer;
+#else
+ value_ptr = (char *) &program[note_strings +
+ GET_DWORD(note_table + (8 * i) + 4)];
+#endif
+
+ if (value != NULL)
+ {
+ jbi_strncpy(value, value_ptr, length);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * We will search for the next note, regardless of the key, and
+ * return both the value and the key
+ */
+
+ i = (int) *offset;
+
+ if ((i >= 0) && (i < (int) note_count))
+ {
+ status = JBIC_SUCCESS;
+
+ if (key != NULL)
+ {
+#if PORT==DOS
+ done = 0;
+ count = 0;
+ long_index = note_strings +
+ GET_DWORD(note_table + (8 * i));
+
+ while ((count < length) && !done)
+ {
+ key[count] = GET_BYTE(long_index);
+ if (key[count] == '\0') done = 1;
+ ++long_index;
+ ++count;
+ }
+#else
+ jbi_strncpy(key, (char *) &program[note_strings +
+ GET_DWORD(note_table + (8 * i))], length);
+#endif
+ }
+
+ if (value != NULL)
+ {
+#if PORT==DOS
+ done = 0;
+ count = 0;
+ long_index = note_strings +
+ GET_DWORD(note_table + (8 * i) + 4);
+
+ while ((count < length) && !done)
+ {
+ value[count] = GET_BYTE(long_index);
+ if (value[count] == '\0') done = 1;
+ ++long_index;
+ ++count;
+ }
+#else
+ jbi_strncpy(value, (char *) &program[note_strings +
+ GET_DWORD(note_table + (8 * i) + 4)], length);
+#endif
+ }
+
+ *offset = i + 1;
+ }
+ }
+ }
+
+ return (status);
+}
+
+/****************************************************************************/
+/* */
+
+JBI_RETURN_TYPE jbi_check_crc
+(
+ PROGRAM_PTR program,
+ long program_size,
+ unsigned short *expected_crc,
+ unsigned short *actual_crc
+)
+
+/* */
+/* Description: This function reads the entire input file and computes */
+/* the CRC of everything up to the CRC field. */
+/* */
+/* Returns: JBIC_SUCCESS for success, JBIC_CRC_ERROR for failure */
+/* */
+/****************************************************************************/
+{
+ JBI_RETURN_TYPE status = JBIC_SUCCESS;
+ unsigned short local_expected, local_actual, shift_reg = 0xffff;
+ int bit, feedback;
+ unsigned char databyte;
+ unsigned long i;
+ unsigned long crc_section = 0L;
+ unsigned long first_word = 0L;
+ int version = 0;
+ int delta = 0;
+
+#if PORT==DOS
+ jbi_program = program;
+#endif
+
+ if (program_size > 52L)
+ {
+ first_word = GET_DWORD(0);
+ version = (int) (first_word & 1L);
+ delta = version * 8;
+
+ crc_section = GET_DWORD(32 + delta);
+ }
+
+ if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+ {
+ status = JBIC_IO_ERROR;
+ }
+
+ if (crc_section >= (unsigned long) program_size)
+ {
+ status = JBIC_IO_ERROR;
+ }
+
+ if (status == JBIC_SUCCESS)
+ {
+ local_expected = (unsigned short) GET_WORD(crc_section);
+ if (expected_crc != NULL) *expected_crc = local_expected;
+
+ for (i = 0; i < crc_section; ++i)
+ {
+ databyte = GET_BYTE(i);
+ for (bit = 0; bit < 8; bit++) /* compute for each bit */
+ {
+ feedback = (databyte ^ shift_reg) & 0x01;
+ shift_reg >>= 1; /* shift the shift register */
+ if (feedback) shift_reg ^= 0x8408; /* invert selected bits */
+ databyte >>= 1; /* get the next bit of input_byte */
+ }
+ }
+
+ local_actual = (unsigned short) ~shift_reg;
+ if (actual_crc != NULL) *actual_crc = local_actual;
+
+ if (local_expected != local_actual)
+ {
+ status = JBIC_CRC_ERROR;
+ }
+ }
+
+ return (status);
+}
+
+JBI_RETURN_TYPE jbi_get_file_info
+(
+ PROGRAM_PTR program,
+ long program_size,
+ int *format_version,
+ int *action_count,
+ int *procedure_count
+)
+{
+ JBI_RETURN_TYPE status = JBIC_IO_ERROR;
+ unsigned long first_word = 0;
+ int version = 0;
+
+#if PORT==DOS
+ jbi_program = program;
+#endif
+
+ /*
+ * Read header information
+ */
+ if (program_size > 52L)
+ {
+ first_word = GET_DWORD(0);
+
+ if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L))
+ {
+ status = JBIC_SUCCESS;
+
+ version = (int) (first_word & 1L);
+ *format_version = version + 1;
+
+ if (version > 0)
+ {
+ *action_count = (int) GET_DWORD(48);
+ *procedure_count = (int) GET_DWORD(52);
+ }
+ }
+
+ }
+
+ return (status);
+}
+
+JBI_RETURN_TYPE jbi_get_action_info
+(
+ PROGRAM_PTR program,
+ long program_size,
+ int index,
+ char **name,
+ char **description,
+ JBI_PROCINFO **procedure_list
+)
+{
+ JBI_RETURN_TYPE status = JBIC_IO_ERROR;
+ JBI_PROCINFO *procptr = NULL;
+ JBI_PROCINFO *tmpptr = NULL;
+ unsigned long first_word = 0L;
+ unsigned long action_table = 0L;
+ unsigned long proc_table = 0L;
+ unsigned long string_table = 0L;
+ unsigned long note_strings = 0L;
+ unsigned long action_count = 0L;
+ unsigned long proc_count = 0L;
+ unsigned long act_name_id = 0L;
+ unsigned long act_desc_id = 0L;
+ unsigned long act_proc_id = 0L;
+ unsigned long act_proc_name = 0L;
+ unsigned char act_proc_attribute = 0;
+
+#if PORT==DOS
+ int i, length;
+ jbi_program = program;
+#endif
+
+ /*
+ * Read header information
+ */
+ if (program_size > 52L)
+ {
+ first_word = GET_DWORD(0);
+
+ if (first_word == 0x4A414D01L)
+ {
+ action_table = GET_DWORD(4);
+ proc_table = GET_DWORD(8);
+ string_table = GET_DWORD(12);
+ note_strings = GET_DWORD(16);
+ action_count = GET_DWORD(48);
+ proc_count = GET_DWORD(52);
+
+ if (index < (int) action_count)
+ {
+ act_name_id = GET_DWORD(action_table + (12 * index));
+ act_desc_id = GET_DWORD(action_table + (12 * index) + 4);
+ act_proc_id = GET_DWORD(action_table + (12 * index) + 8);
+
+#if PORT==DOS
+ length = 0;
+ while (GET_BYTE(string_table + act_name_id + length) != 0) ++length;
+ *name = jbi_malloc(length + 1);
+ if (*name == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ for (i = 0; i < length; ++i)
+ {
+ (*name)[i] = GET_BYTE(string_table + act_name_id + i);
+ }
+ (*name)[length] = '\0';
+ }
+#else
+ *name = (char *) &program[string_table + act_name_id];
+#endif
+
+ if (act_desc_id < (note_strings - string_table))
+ {
+#if PORT==DOS
+ length = 0;
+ while (GET_BYTE(string_table + act_desc_id + length) != 0) ++length;
+ *description = jbi_malloc(length + 1);
+ if (*description == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ for (i = 0; i < length; ++i)
+ {
+ (*description)[i] = GET_BYTE(string_table + act_desc_id + i);
+ }
+ (*description)[length] = '\0';
+ }
+#else
+ *description = (char *) &program[string_table + act_desc_id];
+#endif
+ }
+
+ do
+ {
+ act_proc_name = GET_DWORD(proc_table + (13 * act_proc_id));
+ act_proc_attribute = (unsigned char)
+ (GET_BYTE(proc_table + (13 * act_proc_id) + 8) & 0x03);
+
+ procptr = (JBI_PROCINFO *) jbi_malloc(sizeof(JBI_PROCINFO));
+
+ if (procptr == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+#if PORT==DOS
+ length = 0;
+ while (GET_BYTE(string_table + act_proc_name + length) != 0) ++length;
+ procptr->name = jbi_malloc(length + 1);
+ if (procptr->name == NULL)
+ {
+ status = JBIC_OUT_OF_MEMORY;
+ }
+ else
+ {
+ for (i = 0; i < length; ++i)
+ {
+ procptr->name[i] =
+ GET_BYTE(string_table + act_proc_name + i);
+ }
+ procptr->name[length] = '\0';
+ }
+#else
+ procptr->name = (char *)
+ &program[string_table + act_proc_name];
+#endif
+ procptr->attributes = act_proc_attribute;
+ procptr->next = NULL;
+
+ /* add record to end of linked list */
+ if (*procedure_list == NULL)
+ {
+ *procedure_list = procptr;
+ }
+ else
+ {
+ tmpptr = *procedure_list;
+ while (tmpptr->next != NULL) tmpptr = tmpptr->next;
+ tmpptr->next = procptr;
+ }
+ }
+
+ act_proc_id =
+ GET_DWORD(proc_table + (13 * act_proc_id) + 4);
+ }
+ while ((act_proc_id != 0) && (act_proc_id < proc_count));
+ }
+ }
+
+ }
+
+ return (status);
+}
diff --git a/common/recipes-utils/jbi/files/code/jbiport.h b/common/recipes-utils/jbi/files/code/jbiport.h
new file mode 100644
index 0000000..885e84d
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbiport.h
@@ -0,0 +1,45 @@
+/****************************************************************************/
+/* */
+/* Module: jbiport.h */
+/* */
+/* Copyright (C) Altera Corporation 2000-2001 */
+/* */
+/* Description: Defines porting macros */
+/* */
+/****************************************************************************/
+
+#ifndef INC_JBIPORT_H
+#define INC_JBIPORT_H
+
+/*
+* PORT defines the target platform: DOS, WINDOWS, UNIX, or EMBEDDED
+*
+* PORT = DOS means a 16-bit DOS console-mode application
+*
+* PORT = WINDOWS means a 32-bit WIN32 console-mode application for
+* Windows 95, 98, 2000, ME or NT. On NT this will use the
+* DeviceIoControl() API to access the Parallel Port.
+*
+* PORT = UNIX means any UNIX system. BitBlaster access is support via
+* the standard ANSI system calls open(), read(), write().
+* The ByteBlaster is not supported.
+*
+* PORT = EMBEDDED means all DOS, WINDOWS, and UNIX code is excluded.
+* Remaining code supports 16 and 32-bit compilers.
+* Additional porting steps may be necessary. See readme
+* file for more details.
+*/
+
+#define DOS 2
+#define WINDOWS 3
+#define UNIX 4
+#define EMBEDDED 5
+
+#ifndef PORT
+/* change this line to build a different port */
+#define PORT UNIX
+#endif
+
+#define OPENBMC
+
+#endif /* INC_JBIPORT_H */
diff --git a/common/recipes-utils/jbi/files/code/jbistub.c b/common/recipes-utils/jbi/files/code/jbistub.c
new file mode 100644
index 0000000..87e9066
--- /dev/null
+++ b/common/recipes-utils/jbi/files/code/jbistub.c
@@ -0,0 +1,2222 @@
+/****************************************************************************/
+/* */
+/* Module: jbistub.c */
+/* */
+/* Copyright (C) Altera Corporation 1997-2001 */
+/* */
+/* Description: Jam STAPL ByteCode Player main source file */
+/* */
+/* Supports Altera ByteBlaster hardware download cable */
+/* on Windows 95 and Windows NT operating systems. */
+/* (A device driver is required for Windows NT.) */
+/* */
+/* Also supports BitBlaster hardware download cable on */
+/* Windows 95, Windows NT, and UNIX platforms. */
+/* */
+/* Revisions: 1.1 fixed control port initialization for ByteBlaster */
+/* 2.0 added support for STAPL bytecode format, added code */
+/* to get printer port address from Windows registry */
+/* 2.1 improved messages, fixed delay-calibration bug in */
+/* 16-bit DOS port, added support for "alternative */
+/* cable X", added option to control whether to reset */
+/* the TAP after execution, moved porting macros into */
+/* jbiport.h */
+/* 2.2 added support for static memory */
+/* fixed /W4 warnings */
+/* */
+/****************************************************************************/
+
+#ifndef NO_ALTERA_STDIO
+#define NO_ALTERA_STDIO
+#endif
+
+#if ( _MSC_VER >= 800 )
+#pragma warning(disable:4115)
+#pragma warning(disable:4201)
+#pragma warning(disable:4214)
+#pragma warning(disable:4514)
+#endif
+
+#include "jbiport.h"
+
+#if PORT == WINDOWS
+#include <windows.h>
+#else
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef OPENBMC
+#include <io.h>
+#endif
+#include <fcntl.h>
+#ifndef OPENBMC
+#include <process.h>
+#endif
+#if defined(USE_STATIC_MEMORY)
+ #define N_STATIC_MEMORY_KBYTES ((unsigned int) USE_STATIC_MEMORY)
+ #define N_STATIC_MEMORY_BYTES (N_STATIC_MEMORY_KBYTES * 1024)
+ #define POINTER_ALIGNMENT sizeof(DWORD)
+#else /* USE_STATIC_MEMORY */
+ #include <malloc.h>
+ #define POINTER_ALIGNMENT sizeof(BYTE)
+#endif /* USE_STATIC_MEMORY */
+#include <time.h>
+#ifndef OPENBMC
+#include <conio.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef OPENBMC
+//#define VERBOSE
+//#define DEBUG
+#include <openbmc/gpio.h>
+#include <openbmc/log.h>
+#include <errno.h>
+#endif
+
+#if PORT == DOS
+#include <bios.h>
+#endif
+
+#include "jbiexprt.h"
+
+#if PORT == WINDOWS
+#define PGDC_IOCTL_GET_DEVICE_INFO_PP 0x00166A00L
+#define PGDC_IOCTL_READ_PORT_PP 0x00166A04L
+#define PGDC_IOCTL_WRITE_PORT_PP 0x0016AA08L
+#define PGDC_IOCTL_PROCESS_LIST_PP 0x0016AA1CL
+#define PGDC_READ_INFO 0x0a80
+#define PGDC_READ_PORT 0x0a81
+#define PGDC_WRITE_PORT 0x0a82
+#define PGDC_PROCESS_LIST 0x0a87
+#define PGDC_HDLC_NTDRIVER_VERSION 2
+#define PORT_IO_BUFFER_SIZE 256
+#endif
+
+#if PORT == WINDOWS
+#ifdef __BORLANDC__
+/* create dummy inp() and outp() functions for Borland 32-bit compile */
+WORD inp(WORD address) { address = address; return(0); }
+void outp(WORD address, WORD data) { address = address; data = data; }
+#else
+#pragma intrinsic (inp, outp)
+#endif
+#endif
+
+/*
+* For Borland C compiler (16-bit), set the stack size
+*/
+#if PORT == DOS
+#ifdef __BORLANDC__
+extern unsigned int _stklen = 50000;
+#endif
+#endif
+
+/************************************************************************
+*
+* Global variables
+*/
+
+/* file buffer for Jam STAPL ByteCode input file */
+#if PORT == DOS
+unsigned char **file_buffer = NULL;
+#else
+unsigned char *file_buffer = NULL;
+#endif
+long file_pointer = 0L;
+long file_length = 0L;
+
+/* delay count for one millisecond delay */
+long one_ms_delay = 0L;
+
+/* serial port interface available on all platforms */
+BOOL jtag_hardware_initialized = FALSE;
+char *serial_port_name = NULL;
+BOOL specified_com_port = FALSE;
+int com_port = -1;
+void initialize_jtag_hardware(void);
+void close_jtag_hardware(void);
+
+#ifdef OPENBMC
+int g_tck = -1;
+int g_tms = -1;
+int g_tdo = -1;
+int g_tdi = -1;
+gpio_st g_gpio_tck;
+gpio_st g_gpio_tms;
+gpio_st g_gpio_tdo;
+gpio_st g_gpio_tdi;
+#endif
+
+#if defined(USE_STATIC_MEMORY)
+ unsigned char static_memory_heap[N_STATIC_MEMORY_BYTES] = { 0 };
+#endif /* USE_STATIC_MEMORY */
+
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ unsigned int n_bytes_allocated = 0;
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+
+#if defined(MEM_TRACKER)
+ unsigned int peak_memory_usage = 0;
+ unsigned int peak_allocations = 0;
+ unsigned int n_allocations = 0;
+#if defined(USE_STATIC_MEMORY)
+ unsigned int n_bytes_not_recovered = 0;
+#endif /* USE_STATIC_MEMORY */
+ const DWORD BEGIN_GUARD = 0x01234567;
+ const DWORD END_GUARD = 0x76543210;
+#endif /* MEM_TRACKER */
+
+#if PORT == WINDOWS || PORT == DOS
+/* parallel port interface available on PC only */
+BOOL specified_lpt_port = FALSE;
+BOOL specified_lpt_addr = FALSE;
+int lpt_port = 1;
+int initial_lpt_ctrl = 0;
+WORD lpt_addr = 0x3bc;
+WORD lpt_addr_table[3] = { 0x3bc, 0x378, 0x278 };
+BOOL alternative_cable_l = FALSE;
+BOOL alternative_cable_x = FALSE;
+void write_byteblaster(int port, int data);
+int read_byteblaster(int port);
+#endif
+
+#if PORT==WINDOWS
+#ifndef __BORLANDC__
+WORD lpt_addresses_from_registry[4] = { 0 };
+#endif
+#endif
+
+#if PORT == WINDOWS
+/* variables to manage cached I/O under Windows NT */
+BOOL windows_nt = FALSE;
+int port_io_count = 0;
+HANDLE nt_device_handle = INVALID_HANDLE_VALUE;
+struct PORT_IO_LIST_STRUCT
+{
+ USHORT command;
+ USHORT data;
+} port_io_buffer[PORT_IO_BUFFER_SIZE];
+extern void flush_ports(void);
+BOOL initialize_nt_driver(void);
+#endif
+
+/* function prototypes to allow forward reference */
+extern void delay_loop(long count);
+
+/*
+* This structure stores information about each available vector signal
+*/
+struct VECTOR_LIST_STRUCT
+{
+ char *signal_name;
+ int hardware_bit;
+ int vector_index;
+};
+
+struct VECTOR_LIST_STRUCT vector_list[] =
+{
+ /* add a record here for each vector signal */
+ { "", 0, -1 }
+};
+
+#define VECTOR_SIGNAL_COUNT ((int)(sizeof(vector_list)/sizeof(vector_list[0])))
+
+BOOL verbose = FALSE;
+
+/************************************************************************
+*
+* Customized interface functions for Jam STAPL ByteCode Player I/O:
+*
+* jbi_jtag_io()
+* jbi_message()
+* jbi_delay()
+*/
+
+#ifdef OPENBMC
+
+/*
+ * The threshold (ns) to use spin instead of nanosleep().
+ * Before adding the high resolution timer support, either spin or nanosleep()
+ * will not bring the process wakeup within 10ms. It turns out the system time
+ * update is also controlled by HZ (100).
+ * After I added the high resolution timer support, the spin works as the
+ * system time is updated more frequently. However, nanosleep() solution is
+ * still noticable slower comparing with spin. There could be some kernel
+ * scheduling tweak missing. Did not get time on that yet.
+ * For now, use 10ms as the threshold to determine if spin or nanosleep()
+ * is used.
+ */
+#define SPIN_THRESHOLD (10 * 1000 * 1000)
+#define NANOSEC_IN_SEC (1000 * 1000 * 1000)
+
+static int sleep_ns(unsigned long clk)
+{
+ struct timespec req, rem;
+ int rc = 0;
+ if (clk <= SPIN_THRESHOLD) {
+ struct timespec orig;
+ rc = clock_gettime(CLOCK_MONOTONIC, &req);
+ orig = req;
+ while (!rc && clk) {
+ unsigned long tmp;
+ rc = clock_gettime(CLOCK_MONOTONIC, &rem);
+ tmp = (rem.tv_sec - req.tv_sec) * NANOSEC_IN_SEC;
+ if (rem.tv_nsec >= req.tv_nsec) {
+ tmp += rem.tv_nsec - req.tv_nsec;
+ } else {
+ tmp -= req.tv_nsec - rem.tv_nsec;
+ }
+ if (tmp >= clk) {
+ break;
+ }
+ clk -= tmp;
+ req = rem;
+ }
+ } else {
+ req.tv_sec = 0;
+ req.tv_nsec = clk;
+ while ((rc = nanosleep(&req, &rem)) == -1 && errno == EINTR) {
+ req = rem;
+ }
+ }
+ if (rc == -1) {
+ rc = errno;
+ LOG_ERR(rc, "Failed to sleep %u nanoseconds", clk);
+ }
+ return rc;
+}
+
+int initialize_jtag_gpios()
+{
+ if (gpio_open(&g_gpio_tck, g_tck) || gpio_open(&g_gpio_tms, g_tms)
+ || gpio_open(&g_gpio_tdo, g_tdo) || gpio_open(&g_gpio_tdi, g_tdi)) {
+ return -1;
+ }
+
+ /* change GPIO directions, only TDO is input, all others are output */
+ if (gpio_change_direction(&g_gpio_tck, GPIO_DIRECTION_OUT)
+ || gpio_change_direction(&g_gpio_tms, GPIO_DIRECTION_OUT)
+ || gpio_change_direction(&g_gpio_tdo, GPIO_DIRECTION_IN)
+ || gpio_change_direction(&g_gpio_tdi, GPIO_DIRECTION_OUT)) {
+ return -1;
+ }
+
+ /* set tck, tms, tdi to low */
+ gpio_write(&g_gpio_tck, GPIO_VALUE_LOW);
+ gpio_write(&g_gpio_tms, GPIO_VALUE_LOW);
+ gpio_write(&g_gpio_tdi, GPIO_VALUE_LOW);
+
+ jbi_delay(1);
+
+ LOG_DBG("Opened TCK(GPIO %d), TMS(GPIO %d), TDI(GPIO %d), and TDO(GPIO %d)",
+ g_tck, g_tms, g_tdi, g_tdo);
+
+ return 0;
+}
+
+int jbi_jtag_io(int tms, int tdi, int read_tdo)
+{
+ int tdo = 0;
+
+ if (!jtag_hardware_initialized) {
+ initialize_jtag_gpios();
+ jtag_hardware_initialized = TRUE;
+ }
+
+ gpio_write(&g_gpio_tms, tms ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
+ gpio_write(&g_gpio_tdi, tdi ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW);
+
+ /* sleep 500ns to make sure the signal shows up on wire */
+ sleep_ns(500);
+ /*
+ * if we need to read data, the data should be ready from the
+ * previous clock falling edge. Read it now.
+ */
+ if (read_tdo) {
+ tdo = gpio_read(&g_gpio_tdo) == GPIO_VALUE_HIGH ? 1 : 0;
+ }
+
+ /* do rising edge to clock out the data */
+ gpio_write(&g_gpio_tck, GPIO_VALUE_HIGH);
+ sleep_ns(500);
+ /* do falling edge clocking */
+ gpio_write(&g_gpio_tck, GPIO_VALUE_LOW);
+
+ LOG_VER("tms=%d tdi=%d do_read=%d tdo=%d", tms, tdi, read_tdo, tdo);
+
+ return tdo;
+}
+
+#else
+
+int jbi_jtag_io(int tms, int tdi, int read_tdo)
+{
+ int data = 0;
+ int tdo = 0;
+ int i = 0;
+ int result = 0;
+ char ch_data = 0;
+
+ if (!jtag_hardware_initialized)
+ {
+ initialize_jtag_hardware();
+ jtag_hardware_initialized = TRUE;
+ }
+
+ if (specified_com_port)
+ {
+ ch_data = (char)
+ ((tdi ? 0x01 : 0) | (tms ? 0x02 : 0) | 0x60);
+
+ write(com_port, &ch_data, 1);
+
+ if (read_tdo)
+ {
+ ch_data = 0x7e;
+ write(com_port, &ch_data, 1);
+ for (i = 0; (i < 100) && (result != 1); ++i)
+ {
+ result = read(com_port, &ch_data, 1);
+ }
+ if (result == 1)
+ {
+ tdo = ch_data & 0x01;
+ }
+ else
+ {
+ fprintf(stderr, "Error: BitBlaster not responding\n");
+ }
+ }
+
+ ch_data = (char)
+ ((tdi ? 0x01 : 0) | (tms ? 0x02 : 0) | 0x64);
+
+ write(com_port, &ch_data, 1);
+ }
+ else
+ {
+#if PORT == WINDOWS || PORT == DOS
+ data = (alternative_cable_l ? ((tdi ? 0x01 : 0) | (tms ? 0x04 : 0)) :
+ (alternative_cable_x ? ((tdi ? 0x01 : 0) | (tms ? 0x04 : 0) | 0x10) :
+ ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0))));
+
+ write_byteblaster(0, data);
+
+ if (read_tdo)
+ {
+ tdo = read_byteblaster(1);
+ tdo = (alternative_cable_l ? ((tdo & 0x40) ? 1 : 0) :
+ (alternative_cable_x ? ((tdo & 0x10) ? 1 : 0) :
+ ((tdo & 0x80) ? 0 : 1)));
+ }
+
+ write_byteblaster(0, data | (alternative_cable_l ? 0x02 : (alternative_cable_x ? 0x02: 0x01)));
+
+ write_byteblaster(0, data);
+#else
+ /* parallel port interface not available */
+ tdo = 0;
+#endif
+ }
+
+ return (tdo);
+}
+
+#endif
+
+void jbi_message(char *message_text)
+{
+ puts(message_text);
+ fflush(stdout);
+}
+
+void jbi_export_integer(char *key, long value)
+{
+ if (verbose)
+ {
+ printf("Export: key = \"%s\", value = %ld\n", key, value);
+ fflush(stdout);
+ }
+}
+
+#define HEX_LINE_CHARS 72
+#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
+
+char conv_to_hex(unsigned long value)
+{
+ char c;
+
+ if (value > 9)
+ {
+ c = (char) (value + ('A' - 10));
+ }
+ else
+ {
+ c = (char) (value + '0');
+ }
+
+ return (c);
+}
+
+void jbi_export_boolean_array(char *key, unsigned char *data, long count)
+{
+ char string[HEX_LINE_CHARS + 1];
+ long i, offset;
+ unsigned long size, line, lines, linebits, value, j, k;
+
+ if (verbose)
+ {
+ if (count > HEX_LINE_BITS)
+ {
+ printf("Export: key = \"%s\", %ld bits, value = HEX\n", key, count);
+ lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
+
+ for (line = 0; line < lines; ++line)
+ {
+ if (line < (lines - 1))
+ {
+ linebits = HEX_LINE_BITS;
+ size = HEX_LINE_CHARS;
+ offset = count - ((line + 1) * HEX_LINE_BITS);
+ }
+ else
+ {
+ linebits = count - ((lines - 1) * HEX_LINE_BITS);
+ size = (linebits + 3) / 4;
+ offset = 0L;
+ }
+
+ string[size] = '\0';
+ j = size - 1;
+ value = 0;
+
+ for (k = 0; k < linebits; ++k)
+ {
+ i = k + offset;
+ if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
+ if ((i & 3) == 3)
+ {
+ string[j] = conv_to_hex(value);
+ value = 0;
+ --j;
+ }
+ }
+ if ((k & 3) > 0) string[j] = conv_to_hex(value);
+
+ printf("%s\n", string);
+ }
+
+ fflush(stdout);
+ }
+ else
+ {
+ size = (count + 3) / 4;
+ string[size] = '\0';
+ j = size - 1;
+ value = 0;
+
+ for (i = 0; i < count; ++i)
+ {
+ if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
+ if ((i & 3) == 3)
+ {
+ string[j] = conv_to_hex(value);
+ value = 0;
+ --j;
+ }
+ }
+ if ((i & 3) > 0) string[j] = conv_to_hex(value);
+
+ printf("Export: key = \"%s\", %ld bits, value = HEX %s\n",
+ key, count, string);
+ fflush(stdout);
+ }
+ }
+}
+
+void jbi_delay(long microseconds)
+{
+#if PORT == WINDOWS
+ /* if Windows NT, flush I/O cache buffer before delay loop */
+ if (windows_nt && (port_io_count > 0)) flush_ports();
+#endif
+
+#ifdef OPENBMC
+ sleep_ns(microseconds * 1000);
+#else
+ delay_loop(microseconds *
+ ((one_ms_delay / 1000L) + ((one_ms_delay % 1000L) ? 1 : 0)));
+#endif
+}
+
+int jbi_vector_map
+(
+ int signal_count,
+ char **signals
+)
+{
+ int signal, vector, ch_index, diff;
+ int matched_count = 0;
+ char l, r;
+
+ for (vector = 0; (vector < VECTOR_SIGNAL_COUNT); ++vector)
+ {
+ vector_list[vector].vector_index = -1;
+ }
+
+ for (signal = 0; signal < signal_count; ++signal)
+ {
+ diff = 1;
+ for (vector = 0; (diff != 0) && (vector < VECTOR_SIGNAL_COUNT);
+ ++vector)
+ {
+ if (vector_list[vector].vector_index == -1)
+ {
+ ch_index = 0;
+ do
+ {
+ l = signals[signal][ch_index];
+ r = vector_list[vector].signal_name[ch_index];
+ diff = (((l >= 'a') && (l <= 'z')) ? (l - ('a' - 'A')) : l)
+ - (((r >= 'a') && (r <= 'z')) ? (r - ('a' - 'A')) : r);
+ ++ch_index;
+ }
+ while ((diff == 0) && (l != '\0') && (r != '\0'));
+
+ if (diff == 0)
+ {
+ vector_list[vector].vector_index = signal;
+ ++matched_count;
+ }
+ }
+ }
+ }
+
+ return (matched_count);
+}
+
+int jbi_vector_io
+(
+ int signal_count,
+ long *dir_vect,
+ long *data_vect,
+ long *capture_vect
+)
+{
+ int signal, vector, bit;
+ int matched_count = 0;
+ int data = 0;
+ int mask = 0;
+ int dir = 0;
+ int i = 0;
+ int result = 0;
+ char ch_data = 0;
+
+ if (!jtag_hardware_initialized)
+ {
+ initialize_jtag_hardware();
+ jtag_hardware_initialized = TRUE;
+ }
+
+ /*
+ * Collect information about output signals
+ */
+ for (vector = 0; vector < VECTOR_SIGNAL_COUNT; ++vector)
+ {
+ signal = vector_list[vector].vector_index;
+
+ if ((signal >= 0) && (signal < signal_count))
+ {
+ bit = (1 << vector_list[vector].hardware_bit);
+
+ mask |= bit;
+ if (data_vect[signal >> 5] & (1L << (signal & 0x1f))) data |= bit;
+ if (dir_vect[signal >> 5] & (1L << (signal & 0x1f))) dir |= bit;
+
+ ++matched_count;
+ }
+ }
+
+ /*
+ * Write outputs to hardware interface, if any
+ */
+ if (dir != 0)
+ {
+ if (specified_com_port)
+ {
+ ch_data = (char) (((data >> 6) & 0x01) | (data & 0x02) |
+ ((data << 2) & 0x04) | ((data << 3) & 0x08) | 0x60);
+ write(com_port, &ch_data, 1);
+ }
+ else
+ {
+#if PORT == WINDOWS || PORT == DOS
+
+ write_byteblaster(0, data);
+
+#endif
+ }
+ }
+
+ /*
+ * Read the input signals and save information in capture_vect[]
+ */
+ if ((dir != mask) && (capture_vect != NULL))
+ {
+ if (specified_com_port)
+ {
+ ch_data = 0x7e;
+ write(com_port, &ch_data, 1);
+ for (i = 0; (i < 100) && (result != 1); ++i)
+ {
+ result = read(com_port, &ch_data, 1);
+ }
+ if (result == 1)
+ {
+ data = ((ch_data << 7) & 0x80) | ((ch_data << 3) & 0x10);
+ }
+ else
+ {
+ fprintf(stderr, "Error: BitBlaster not responding\n");
+ }
+ }
+ else
+ {
+#if PORT == WINDOWS || PORT == DOS
+
+ data = read_byteblaster(1) ^ 0x80; /* parallel port inverts bit 7 */
+
+#endif
+ }
+
+ for (vector = 0; vector < VECTOR_SIGNAL_COUNT; ++vector)
+ {
+ signal = vector_list[vector].vector_index;
+
+ if ((signal >= 0) && (signal < signal_count))
+ {
+ bit = (1 << vector_list[vector].hardware_bit);
+
+ if ((dir & bit) == 0) /* if it is an input signal... */
+ {
+ if (data & bit)
+ {
+ capture_vect[signal >> 5] |= (1L << (signal & 0x1f));
+ }
+ else
+ {
+ capture_vect[signal >> 5] &= ~(unsigned long)
+ (1L << (signal & 0x1f));
+ }
+ }
+ }
+ }
+ }
+
+ return (matched_count);
+}
+
+void *jbi_malloc(unsigned int size)
+{
+ unsigned int n_bytes_to_allocate =
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ sizeof(unsigned int) +
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+#if defined(MEM_TRACKER)
+ (2 * sizeof(DWORD)) +
+#endif /* MEM_TRACKER */
+ (POINTER_ALIGNMENT * ((size + POINTER_ALIGNMENT - 1) / POINTER_ALIGNMENT));
+
+ unsigned char *ptr = 0;
+
+
+#if defined(MEM_TRACKER)
+ if ((n_bytes_allocated + n_bytes_to_allocate) > peak_memory_usage)
+ {
+ peak_memory_usage = n_bytes_allocated + n_bytes_to_allocate;
+ }
+ if ((n_allocations + 1) > peak_allocations)
+ {
+ peak_allocations = n_allocations + 1;
+ }
+#endif /* MEM_TRACKER */
+
+#if defined(USE_STATIC_MEMORY)
+ if ((n_bytes_allocated + n_bytes_to_allocate) <= N_STATIC_MEMORY_BYTES)
+ {
+ ptr = (&(static_memory_heap[n_bytes_allocated]));
+ }
+#else /* USE_STATIC_MEMORY */
+ ptr = (unsigned char *) malloc(n_bytes_to_allocate);
+#endif /* USE_STATIC_MEMORY */
+
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ if (ptr != 0)
+ {
+ unsigned int i = 0;
+
+#if defined(MEM_TRACKER)
+ for (i = 0; i < sizeof(DWORD); ++i)
+ {
+ *ptr = (unsigned char) (BEGIN_GUARD >> (8 * i));
+ ++ptr;
+ }
+#endif /* MEM_TRACKER */
+
+ for (i = 0; i < sizeof(unsigned int); ++i)
+ {
+ *ptr = (unsigned char) (size >> (8 * i));
+ ++ptr;
+ }
+
+#if defined(MEM_TRACKER)
+ for (i = 0; i < sizeof(DWORD); ++i)
+ {
+ *(ptr + size + i) = (unsigned char) (END_GUARD >> (8 * i));
+ /* don't increment ptr */
+ }
+
+ ++n_allocations;
+#endif /* MEM_TRACKER */
+
+ n_bytes_allocated += n_bytes_to_allocate;
+ }
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+
+ return ptr;
+}
+
+void jbi_free(void *ptr)
+{
+ if
+ (
+#if defined(MEM_TRACKER)
+ (n_allocations > 0) &&
+#endif /* MEM_TRACKER */
+ (ptr != 0)
+ )
+ {
+ unsigned char *tmp_ptr = (unsigned char *) ptr;
+
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ unsigned int n_bytes_to_free = 0;
+ unsigned int i = 0;
+ unsigned int size = 0;
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+#if defined(MEM_TRACKER)
+ DWORD begin_guard = 0;
+ DWORD end_guard = 0;
+
+
+ tmp_ptr -= sizeof(DWORD);
+#endif /* MEM_TRACKER */
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ tmp_ptr -= sizeof(unsigned int);
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+ ptr = tmp_ptr;
+
+#if defined(MEM_TRACKER)
+ for (i = 0; i < sizeof(DWORD); ++i)
+ {
+ begin_guard |= (((DWORD)(*tmp_ptr)) << (8 * i));
+ ++tmp_ptr;
+ }
+#endif /* MEM_TRACKER */
+
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ for (i = 0; i < sizeof(unsigned int); ++i)
+ {
+ size |= (((unsigned int)(*tmp_ptr)) << (8 * i));
+ ++tmp_ptr;
+ }
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+
+#if defined(MEM_TRACKER)
+ tmp_ptr += size;
+
+ for (i = 0; i < sizeof(DWORD); ++i)
+ {
+ end_guard |= (((DWORD)(*tmp_ptr)) << (8 * i));
+ ++tmp_ptr;
+ }
+
+ if ((begin_guard != BEGIN_GUARD) || (end_guard != END_GUARD))
+ {
+ fprintf(stderr, "Error: memory corruption detected for allocation #%d... bad %s guard\n",
+ n_allocations, (begin_guard != BEGIN_GUARD) ? "begin" : "end");
+ }
+
+ --n_allocations;
+#endif /* MEM_TRACKER */
+
+#if defined(USE_STATIC_MEMORY) || defined(MEM_TRACKER)
+ n_bytes_to_free =
+#if defined(MEM_TRACKER)
+ (2 * sizeof(DWORD)) +
+#endif /* MEM_TRACKER */
+ sizeof(unsigned int) +
+ (POINTER_ALIGNMENT * ((size + POINTER_ALIGNMENT - 1) / POINTER_ALIGNMENT));
+#endif /* USE_STATIC_MEMORY || MEM_TRACKER */
+
+#if defined(USE_STATIC_MEMORY)
+ if ((((unsigned long) ptr - (unsigned long) static_memory_heap) + n_bytes_to_free) == (unsigned long) n_bytes_allocated)
+ {
+ n_bytes_allocated -= n_bytes_to_free;
+ }
+#if defined(MEM_TRACKER)
+ else
+ {
+ n_bytes_not_recovered += n_bytes_to_free;
+ }
+#endif /* MEM_TRACKER */
+#else /* USE_STATIC_MEMORY */
+#if defined(MEM_TRACKER)
+ n_bytes_allocated -= n_bytes_to_free;
+#endif /* MEM_TRACKER */
+ free(ptr);
+#endif /* USE_STATIC_MEMORY */
+ }
+#if defined(MEM_TRACKER)
+ else
+ {
+ if (ptr != 0)
+ {
+ fprintf(stderr, "Error: attempt to free unallocated memory\n");
+ }
+ }
+#endif /* MEM_TRACKER */
+}
+
+/************************************************************************
+*
+* get_tick_count() -- Get system tick count in milliseconds
+*
+* for DOS, use BIOS function _bios_timeofday()
+* for WINDOWS use GetTickCount() function
+* for UNIX use clock() system function
+*/
+DWORD get_tick_count(void)
+{
+ DWORD tick_count = 0L;
+
+#if PORT == WINDOWS
+ tick_count = GetTickCount();
+#elif PORT == DOS
+ _bios_timeofday(_TIME_GETCLOCK, (long *)&tick_count);
+ tick_count *= 55L; /* convert to milliseconds */
+#else
+ /* assume clock() function returns microseconds */
+ tick_count = (DWORD) (clock() / 1000L);
+#endif
+
+ return (tick_count);
+}
+
+#define DELAY_SAMPLES 10
+#define DELAY_CHECK_LOOPS 10000
+
+void calibrate_delay(void)
+{
+ int sample = 0;
+ int count = 0;
+ DWORD tick_count1 = 0L;
+ DWORD tick_count2 = 0L;
+
+ one_ms_delay = 0L;
+
+#if PORT == WINDOWS || PORT == DOS || defined(OPENBMC)
+ for (sample = 0; sample < DELAY_SAMPLES; ++sample)
+ {
+ count = 0;
+ tick_count1 = get_tick_count();
+ while ((tick_count2 = get_tick_count()) == tick_count1) {};
+ do { delay_loop(DELAY_CHECK_LOOPS); count++; } while
+ ((tick_count1 = get_tick_count()) == tick_count2);
+ one_ms_delay += ((DELAY_CHECK_LOOPS * (DWORD)count) /
+ (tick_count1 - tick_count2));
+ }
+
+ one_ms_delay /= DELAY_SAMPLES;
+#else
+ /* This is system-dependent! Update this number for target system */
+ one_ms_delay = 1000L;
+#endif
+}
+
+char *error_text[] =
+{
+/* JBIC_SUCCESS 0 */ "success",
+/* JBIC_OUT_OF_MEMORY 1 */ "out of memory",
+/* JBIC_IO_ERROR 2 */ "file access error",
+/* JAMC_SYNTAX_ERROR 3 */ "syntax error",
+/* JBIC_UNEXPECTED_END 4 */ "unexpected end of file",
+/* JBIC_UNDEFINED_SYMBOL 5 */ "undefined symbol",
+/* JAMC_REDEFINED_SYMBOL 6 */ "redefined symbol",
+/* JBIC_INTEGER_OVERFLOW 7 */ "integer overflow",
+/* JBIC_DIVIDE_BY_ZERO 8 */ "divide by zero",
+/* JBIC_CRC_ERROR 9 */ "CRC mismatch",
+/* JBIC_INTERNAL_ERROR 10 */ "internal error",
+/* JBIC_BOUNDS_ERROR 11 */ "bounds error",
+/* JAMC_TYPE_MISMATCH 12 */ "type mismatch",
+/* JAMC_ASSIGN_TO_CONST 13 */ "assignment to constant",
+/* JAMC_NEXT_UNEXPECTED 14 */ "NEXT unexpected",
+/* JAMC_POP_UNEXPECTED 15 */ "POP unexpected",
+/* JAMC_RETURN_UNEXPECTED 16 */ "RETURN unexpected",
+/* JAMC_ILLEGAL_SYMBOL 17 */ "illegal symbol name",
+/* JBIC_VECTOR_MAP_FAILED 18 */ "vector signal name not found",
+/* JBIC_USER_ABORT 19 */ "execution cancelled",
+/* JBIC_STACK_OVERFLOW 20 */ "stack overflow",
+/* JBIC_ILLEGAL_OPCODE 21 */ "illegal instruction code",
+/* JAMC_PHASE_ERROR 22 */ "phase error",
+/* JAMC_SCOPE_ERROR 23 */ "scope error",
+/* JBIC_ACTION_NOT_FOUND 24 */ "action not found",
+};
+
+#define MAX_ERROR_CODE (int)((sizeof(error_text)/sizeof(error_text[0]))+1)
+
+/************************************************************************/
+
+int main(int argc, char **argv)
+{
+ BOOL help = FALSE;
+ BOOL error = FALSE;
+ char *filename = NULL;
+ long offset = 0L;
+ long error_address = 0L;
+ JBI_RETURN_TYPE crc_result = JBIC_SUCCESS;
+ JBI_RETURN_TYPE exec_result = JBIC_SUCCESS;
+ unsigned short expected_crc = 0;
+ unsigned short actual_crc = 0;
+ char key[33] = {0};
+ char value[257] = {0};
+ int exit_status = 0;
+ int arg = 0;
+ int exit_code = 0;
+ int format_version = 0;
+ time_t start_time = 0;
+ time_t end_time = 0;
+ int time_delta = 0;
+ char *workspace = NULL;
+ char *action = NULL;
+ char *init_list[10];
+ int init_count = 0;
+ FILE *fp = NULL;
+ struct stat sbuf;
+ long workspace_size = 0;
+ char *exit_string = NULL;
+ int reset_jtag = 1;
+ int execute_program = 1;
+ int action_count = 0;
+ int procedure_count = 0;
+ int index = 0;
+ char *action_name = NULL;
+ char *description = NULL;
+ JBI_PROCINFO *procedure_list = NULL;
+ JBI_PROCINFO *procptr = NULL;
+
+ verbose = FALSE;
+
+ init_list[0] = NULL;
+
+ /* print out the version string and copyright message */
+ fprintf(stderr, "Jam STAPL ByteCode Player Version 2.2\nCopyright (C) 1998-2001 Altera Corporation\n\n");
+
+ for (arg = 1; arg < argc; arg++)
+ {
+#if PORT == UNIX
+ if (argv[arg][0] == '-')
+#else
+ if ((argv[arg][0] == '-') || (argv[arg][0] == '/'))
+#endif
+ {
+ switch(toupper(argv[arg][1]))
+ {
+ case 'A': /* set action name */
+ if (action == NULL)
+ {
+ action = &argv[arg][2];
+ }
+ else
+ {
+ error = TRUE;
+ }
+ break;
+
+#if PORT == WINDOWS || PORT == DOS
+ case 'C': /* Use alternative ISP download cable */
+ if(toupper(argv[arg][2]) == 'L')
+ alternative_cable_l = TRUE;
+ else if(toupper(argv[arg][2]) == 'X')
+ alternative_cable_x = TRUE;
+ break;
+#endif
+
+ case 'D': /* initialization list */
+ if (argv[arg][2] == '"')
+ {
+ init_list[init_count] = &argv[arg][3];
+ }
+ else
+ {
+ init_list[init_count] = &argv[arg][2];
+ }
+ init_list[++init_count] = NULL;
+ break;
+
+#if PORT == WINDOWS || PORT == DOS
+ case 'P': /* set LPT port address */
+ specified_lpt_port = TRUE;
+ if (sscanf(&argv[arg][2], "%d", &lpt_port) != 1) error = TRUE;
+ if ((lpt_port < 1) || (lpt_port > 3)) error = TRUE;
+ if (error)
+ {
+ if (sscanf(&argv[arg][2], "%x", &lpt_port) == 1)
+ {
+ if ((lpt_port == 0x3bc) ||
+ (lpt_port == 0x378) ||
+ (lpt_port == 0x278))
+ {
+ error = FALSE;
+ specified_lpt_addr = TRUE;
+ lpt_addr = (WORD) lpt_port;
+ lpt_port = 1;
+ }
+ }
+ }
+ break;
+#endif
+
+ case 'R': /* don't reset the JTAG chain after use */
+ reset_jtag = 0;
+ break;
+
+#ifdef OPENBMC
+ case 'G': /* GPIO directory */
+ switch (toupper(argv[arg][2])) {
+ case 'C':
+ g_tck = atoi(&argv[arg][3]);
+ break;
+ case 'S':
+ g_tms = atoi(&argv[arg][3]);
+ break;
+ case 'I':
+ g_tdi = atoi(&argv[arg][3]);
+ break;
+ case 'O':
+ g_tdo = atoi(&argv[arg][3]);
+ break;
+ }
+ break;
+#else
+ case 'S': /* set serial port address */
+ serial_port_name = &argv[arg][2];
+ specified_com_port = TRUE;
+ break;
+#endif
+
+ case 'M': /* set memory size */
+ if (sscanf(&argv[arg][2], "%ld", &workspace_size) != 1)
+ error = TRUE;
+ if (workspace_size == 0) error = TRUE;
+ break;
+
+ case 'H': /* help */
+ help = TRUE;
+ break;
+
+ case 'V': /* verbose */
+ verbose = TRUE;
+ break;
+
+ case 'I': /* show info only, do not execute */
+ verbose = TRUE;
+ execute_program = 0;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ /* it's a filename */
+ if (filename == NULL)
+ {
+ filename = argv[arg];
+ }
+ else
+ {
+ /* error -- we already found a filename */
+ error = TRUE;
+ }
+ }
+
+ if (error)
+ {
+ fprintf(stderr, "Illegal argument: \"%s\"\n", argv[arg]);
+ help = TRUE;
+ error = FALSE;
+ }
+ }
+
+#if PORT == WINDOWS || PORT == DOS
+ if (specified_lpt_port && specified_com_port)
+ {
+ fprintf(stderr, "Error: -s and -p options may not be used together\n\n");
+ help = TRUE;
+ }
+#endif
+
+#ifdef OPENBMC
+ if (execute_program) {
+ if (g_tck == -1 || g_tms == -1 || g_tdo == -1 || g_tdi == -1) {
+ fprintf(stderr, "Error: -gc, -gs, -gi, and -go must be specified\n");
+ help = TRUE;
+ }
+ }
+#endif
+
+ if (help || (filename == NULL))
+ {
+ fprintf(stderr, "Usage: jbi [options] <filename>\n");
+ fprintf(stderr, "\nAvailable options:\n");
+ fprintf(stderr, " -h : show help message\n");
+ fprintf(stderr, " -v : show verbose messages\n");
+ fprintf(stderr, " -i : show file info only - does not execute any action\n");
+ fprintf(stderr, " -a<action> : specify an action name (Jam STAPL)\n");
+ fprintf(stderr, " -d<var=val> : initialize variable to specified value (Jam 1.1)\n");
+ fprintf(stderr, " -d<proc=1> : enable optional procedure (Jam STAPL)\n");
+ fprintf(stderr, " -d<proc=0> : disable recommended procedure (Jam STAPL)\n");
+#if PORT == WINDOWS || PORT == DOS
+ fprintf(stderr, " -p<port> : parallel port number or address (for ByteBlaster)\n");
+ fprintf(stderr, " -c<cable> : alternative download cable compatibility: -cl or -cx\n");
+#endif
+#ifdef OPENBMC
+ fprintf(stderr, " -gc<clock> : GPIO directory for TCK\n");
+ fprintf(stderr, " -gs<clock> : GPIO directory for TMS\n");
+ fprintf(stderr, " -gi<clock> : GPIO directory for TDI\n");
+ fprintf(stderr, " -go<clock> : GPIO directory for TDO\n");
+#else
+ fprintf(stderr, " -s<port> : serial port name (for BitBlaster)\n");
+#endif
+ fprintf(stderr, " -r : don't reset JTAG TAP after use\n");
+ exit_status = 1;
+ }
+ else if ((workspace_size > 0) &&
+ ((workspace = (char *) jbi_malloc((size_t) workspace_size)) == NULL))
+ {
+ fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
+ (int) (workspace_size / 1024L));
+ exit_status = 1;
+ }
+ else if (access(filename, 0) != 0)
+ {
+ fprintf(stderr, "Error: can't access file \"%s\"\n", filename);
+ exit_status = 1;
+ }
+ else
+ {
+ /* get length of file */
+ if (stat(filename, &sbuf) == 0) file_length = sbuf.st_size;
+
+ if ((fp = fopen(filename, "rb")) == NULL)
+ {
+ fprintf(stderr, "Error: can't open file \"%s\"\n", filename);
+ exit_status = 1;
+ }
+ else
+ {
+ /*
+ * Read entire file into a buffer
+ */
+#if PORT == DOS
+ int pages = 1 + (int) (file_length >> 14L);
+ int page;
+ file_buffer = (unsigned char **) jbi_malloc(
+ (size_t) (pages * sizeof(char *)));
+
+ for (page = 0; page < pages; ++page)
+ {
+ /* allocate enough 16K blocks to store the file */
+ file_buffer[page] = (unsigned char *) jbi_malloc (0x4000);
+ if (file_buffer[page] == NULL)
+ {
+ /* flag error and break out of loop */
+ file_buffer = NULL;
+ page = pages;
+ }
+ }
+#else
+ file_buffer = (unsigned char *) jbi_malloc((size_t) file_length);
+#endif
+
+ if (file_buffer == NULL)
+ {
+ fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
+ (int) (file_length / 1024L));
+ exit_status = 1;
+ }
+ else
+ {
+#if PORT == DOS
+ int pages = 1 + (int) (file_length >> 14L);
+ int page;
+ size_t page_size = 0x4000;
+ for (page = 0; (page < pages) && (exit_status == 0); ++page)
+ {
+ if (page == (pages - 1))
+ {
+ /* last page may not be full 16K bytes */
+ page_size = (size_t) (file_length & 0x3fffL);
+ }
+ if (fread(file_buffer[page], 1, page_size, fp) != page_size)
+ {
+ fprintf(stderr, "Error reading file \"%s\"\n", filename);
+ exit_status = 1;
+ }
+ }
+#else
+ if (fread(file_buffer, 1, (size_t) file_length, fp) !=
+ (size_t) file_length)
+ {
+ fprintf(stderr, "Error reading file \"%s\"\n", filename);
+ exit_status = 1;
+ }
+#endif
+ }
+
+ fclose(fp);
+ }
+
+ if (exit_status == 0)
+ {
+ /*
+ * Get Operating System type
+ */
+#if PORT == WINDOWS
+ windows_nt = !(GetVersion() & 0x80000000);
+#endif
+
+ /*
+ * Calibrate the delay loop function
+ */
+ calibrate_delay();
+
+ /*
+ * Check CRC
+ */
+ crc_result = jbi_check_crc(file_buffer, file_length,
+ &expected_crc, &actual_crc);
+
+ if (verbose || (crc_result == JBIC_CRC_ERROR))
+ {
+ switch (crc_result)
+ {
+ case JBIC_SUCCESS:
+ printf("CRC matched: CRC value = %04X\n", actual_crc);
+ break;
+
+ case JBIC_CRC_ERROR:
+ printf("CRC mismatch: expected %04X, actual %04X\n",
+ expected_crc, actual_crc);
+ break;
+
+ case JBIC_UNEXPECTED_END:
+ printf("Expected CRC not found, actual CRC value = %04X\n",
+ actual_crc);
+ break;
+
+ case JBIC_IO_ERROR:
+ printf("Error: File format is not recognized.\n");
+ exit(1);
+ break;
+
+ default:
+ printf("CRC function returned error code %d\n", crc_result);
+ break;
+ }
+ }
+
+ if (verbose)
+ {
+ /*
+ * Display file format version
+ */
+ jbi_get_file_info(file_buffer, file_length,
+ &format_version, &action_count, &procedure_count);
+
+ printf("File format is %s ByteCode format\n",
+ (format_version == 2) ? "Jam STAPL" : "pre-standardized Jam 1.1");
+
+ /*
+ * Dump out NOTE fields
+ */
+ while (jbi_get_note(file_buffer, file_length,
+ &offset, key, value, 256) == 0)
+ {
+ printf("NOTE \"%s\" = \"%s\"\n", key, value);
+ }
+
+ /*
+ * Dump the action table
+ */
+ if ((format_version == 2) && (action_count > 0))
+ {
+ printf("\nActions available in this file:\n");
+
+ for (index = 0; index < action_count; ++index)
+ {
+ jbi_get_action_info(file_buffer, file_length,
+ index, &action_name, &description, &procedure_list);
+
+ if (description == NULL)
+ {
+ printf("%s\n", action_name);
+ }
+ else
+ {
+ printf("%s \"%s\"\n", action_name, description);
+ }
+
+#if PORT == DOS
+ if (action_name != NULL) jbi_free(action_name);
+ if (description != NULL) jbi_free(description);
+#endif
+
+ procptr = procedure_list;
+ while (procptr != NULL)
+ {
+ if (procptr->attributes != 0)
+ {
+ printf(" %s (%s)\n", procptr->name,
+ (procptr->attributes == 1) ?
+ "optional" : "recommended");
+ }
+
+#if PORT == DOS
+ if (procptr->name != NULL) jbi_free(procptr->name);
+#endif
+
+ procedure_list = procptr->next;
+ jbi_free(procptr);
+ procptr = procedure_list;
+ }
+ }
+
+ /* add a blank line before execution messages */
+ if (execute_program) printf("\n");
+ }
+ }
+
+ if (execute_program)
+ {
+ /*
+ * Execute the Jam STAPL ByteCode program
+ */
+ time(&start_time);
+ exec_result = jbi_execute(file_buffer, file_length, workspace,
+ workspace_size, action, init_list, reset_jtag,
+ &error_address, &exit_code, &format_version);
+ time(&end_time);
+
+ if (exec_result == JBIC_SUCCESS)
+ {
+ if (format_version == 2)
+ {
+ switch (exit_code)
+ {
+ case 0: exit_string = "Success"; break;
+ case 1: exit_string = "Checking chain failure"; break;
+ case 2: exit_string = "Reading IDCODE failure"; break;
+ case 3: exit_string = "Reading USERCODE failure"; break;
+ case 4: exit_string = "Reading UESCODE failure"; break;
+ case 5: exit_string = "Entering ISP failure"; break;
+ case 6: exit_string = "Unrecognized device"; break;
+ case 7: exit_string = "Device revision is not supported"; break;
+ case 8: exit_string = "Erase failure"; break;
+ case 9: exit_string = "Device is not blank"; break;
+ case 10: exit_string = "Device programming failure"; break;
+ case 11: exit_string = "Device verify failure"; break;
+ case 12: exit_string = "Read failure"; break;
+ case 13: exit_string = "Calculating checksum failure"; break;
+ case 14: exit_string = "Setting security bit failure"; break;
+ case 15: exit_string = "Querying security bit failure"; break;
+ case 16: exit_string = "Exiting ISP failure"; break;
+ case 17: exit_string = "Performing system test failure"; break;
+ default: exit_string = "Unknown exit code"; break;
+ }
+ }
+ else
+ {
+ switch (exit_code)
+ {
+ case 0: exit_string = "Success"; break;
+ case 1: exit_string = "Illegal initialization values"; break;
+ case 2: exit_string = "Unrecognized device"; break;
+ case 3: exit_string = "Device revision is not supported"; break;
+ case 4: exit_string = "Device programming failure"; break;
+ case 5: exit_string = "Device is not blank"; break;
+ case 6: exit_string = "Device verify failure"; break;
+ case 7: exit_string = "SRAM configuration failure"; break;
+ default: exit_string = "Unknown exit code"; break;
+ }
+ }
+
+ printf("Exit code = %d... %s\n", exit_code, exit_string);
+ }
+ else if ((format_version == 2) &&
+ (exec_result == JBIC_ACTION_NOT_FOUND))
+ {
+ if ((action == NULL) || (*action == '\0'))
+ {
+ printf("Error: no action specified for Jam STAPL file.\nProgram terminated.\n");
+ }
+ else
+ {
+ printf("Error: action \"%s\" is not supported for this Jam STAPL file.\nProgram terminated.\n", action);
+ }
+ }
+ else if (exec_result < MAX_ERROR_CODE)
+ {
+ printf("Error at address %ld: %s.\nProgram terminated.\n",
+ error_address, error_text[exec_result]);
+ }
+ else
+ {
+ printf("Unknown error code %ld\n", exec_result);
+ }
+
+ /*
+ * Print out elapsed time
+ */
+ if (verbose)
+ {
+ time_delta = (int) (end_time - start_time);
+ printf("Elapsed time = %02u:%02u:%02u\n",
+ time_delta / 3600, /* hours */
+ (time_delta % 3600) / 60, /* minutes */
+ time_delta % 60); /* seconds */
+ }
+ }
+ }
+ }
+
+ if (jtag_hardware_initialized) close_jtag_hardware();
+
+ if (workspace != NULL) jbi_free(workspace);
+ if (file_buffer != NULL) jbi_free(file_buffer);
+
+#if defined(MEM_TRACKER)
+ if (verbose)
+ {
+#if defined(USE_STATIC_MEMORY)
+ fprintf(stdout, "Memory Usage Info: static memory size = %ud (%dKB)\n", N_STATIC_MEMORY_BYTES, N_STATIC_MEMORY_KBYTES);
+#endif /* USE_STATIC_MEMORY */
+ fprintf(stdout, "Memory Usage Info: peak memory usage = %ud (%dKB)\n", peak_memory_usage, (peak_memory_usage + 1023) / 1024);
+ fprintf(stdout, "Memory Usage Info: peak allocations = %d\n", peak_allocations);
+#if defined(USE_STATIC_MEMORY)
+ if ((n_bytes_allocated - n_bytes_not_recovered) != 0)
+ {
+ fprintf(stdout, "Memory Usage Info: bytes still allocated = %d (%dKB)\n", (n_bytes_allocated - n_bytes_not_recovered), ((n_bytes_allocated - n_bytes_not_recovered) + 1023) / 1024);
+ }
+#else /* USE_STATIC_MEMORY */
+ if (n_bytes_allocated != 0)
+ {
+ fprintf(stdout, "Memory Usage Info: bytes still allocated = %d (%dKB)\n", n_bytes_allocated, (n_bytes_allocated + 1023) / 1024);
+ }
+#endif /* USE_STATIC_MEMORY */
+ if (n_allocations != 0)
+ {
+ fprintf(stdout, "Memory Usage Info: allocations not freed = %d\n", n_allocations);
+ }
+ }
+#endif /* MEM_TRACKER */
+
+ return (exit_status);
+}
+
+#if PORT==WINDOWS
+#ifndef __BORLANDC__
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* SEARCH_DYN_DATA
+*
+* Searches recursively in Windows 95/98 Registry for parallel port info
+* under HKEY_DYN_DATA registry key. Called by search_local_machine().
+*/
+void search_dyn_data
+(
+ char *dd_path,
+ char *hardware_key,
+ int lpt
+)
+{
+ DWORD index;
+ DWORD size;
+ DWORD type;
+ LONG result;
+ HKEY key;
+ int length;
+ WORD address;
+ char buffer[1024];
+ FILETIME last_write = {0};
+ WORD *word_ptr;
+ int i;
+
+ length = strlen(dd_path);
+
+ if (RegOpenKeyEx(
+ HKEY_DYN_DATA,
+ dd_path,
+ 0L,
+ KEY_READ,
+ &key)
+ == ERROR_SUCCESS)
+ {
+ size = 1023;
+
+ if (RegQueryValueEx(
+ key,
+ "HardWareKey",
+ NULL,
+ &type,
+ (unsigned char *) buffer,
+ &size)
+ == ERROR_SUCCESS)
+ {
+ if ((type == REG_SZ) && (stricmp(buffer, hardware_key) == 0))
+ {
+ size = 1023;
+
+ if (RegQueryValueEx(
+ key,
+ "Allocation",
+ NULL,
+ &type,
+ (unsigned char *) buffer,
+ &size)
+ == ERROR_SUCCESS)
+ {
+ /*
+ * By "inspection", I have found five cases: size 32, 48,
+ * 56, 60, and 80 bytes. The port address seems to be
+ * located at different offsets in the buffer for these
+ * five cases, as shown below. If a valid port address
+ * is not found, or the size is not one of these known
+ * sizes, then I search through the entire buffer and
+ * look for a value which is a valid port address.
+ */
+
+ word_ptr = (WORD *) buffer;
+
+ if ((type == REG_BINARY) && (size == 32))
+ {
+ address = word_ptr[10];
+ }
+ else if ((type == REG_BINARY) && (size == 48))
+ {
+ address = word_ptr[18];
+ }
+ else if ((type == REG_BINARY) && (size == 56))
+ {
+ address = word_ptr[22];
+ }
+ else if ((type == REG_BINARY) && (size == 60))
+ {
+ address = word_ptr[24];
+ }
+ else if ((type == REG_BINARY) && (size == 80))
+ {
+ address = word_ptr[24];
+ }
+ else address = 0;
+
+ /* if not found, search through entire buffer */
+ i = 0;
+ while ((i < (int) (size / 2)) &&
+ (address != 0x278) &&
+ (address != 0x27C) &&
+ (address != 0x378) &&
+ (address != 0x37C) &&
+ (address != 0x3B8) &&
+ (address != 0x3BC))
+ {
+ if ((word_ptr[i] == 0x278) ||
+ (word_ptr[i] == 0x27C) ||
+ (word_ptr[i] == 0x378) ||
+ (word_ptr[i] == 0x37C) ||
+ (word_ptr[i] == 0x3B8) ||
+ (word_ptr[i] == 0x3BC))
+ {
+ address = word_ptr[i];
+ }
+ ++i;
+ }
+
+ if ((address == 0x278) ||
+ (address == 0x27C) ||
+ (address == 0x378) ||
+ (address == 0x37C) ||
+ (address == 0x3B8) ||
+ (address == 0x3BC))
+ {
+ lpt_addresses_from_registry[lpt] = address;
+ }
+ }
+ }
+ }
+
+ index = 0;
+
+ do
+ {
+ size = 1023;
+
+ result = RegEnumKeyEx(
+ key,
+ index++,
+ buffer,
+ &size,
+ NULL,
+ NULL,
+ NULL,
+ &last_write);
+
+ if (result == ERROR_SUCCESS)
+ {
+ dd_path[length] = '\\';
+ dd_path[length + 1] = '\0';
+ strcpy(&dd_path[length + 1], buffer);
+
+ search_dyn_data(dd_path, hardware_key, lpt);
+
+ dd_path[length] = '\0';
+ }
+ }
+ while (result == ERROR_SUCCESS);
+
+ RegCloseKey(key);
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* SEARCH_LOCAL_MACHINE
+*
+* Searches recursively in Windows 95/98 Registry for parallel port info
+* under HKEY_LOCAL_MACHINE\Enum. When parallel port is found, calls
+* search_dyn_data() to get the port address.
+*/
+void search_local_machine
+(
+ char *lm_path,
+ char *dd_path
+)
+{
+ DWORD index;
+ DWORD size;
+ DWORD type;
+ LONG result;
+ HKEY key;
+ int length;
+ char buffer[1024];
+ FILETIME last_write = {0};
+
+ length = strlen(lm_path);
+
+ if (RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ lm_path,
+ 0L,
+ KEY_READ,
+ &key)
+ == ERROR_SUCCESS)
+ {
+ size = 1023;
+
+ if (RegQueryValueEx(
+ key,
+ "PortName",
+ NULL,
+ &type,
+ (unsigned char *) buffer,
+ &size)
+ == ERROR_SUCCESS)
+ {
+ if ((type == REG_SZ) &&
+ (size == 5) &&
+ (buffer[0] == 'L') &&
+ (buffer[1] == 'P') &&
+ (buffer[2] == 'T') &&
+ (buffer[3] >= '1') &&
+ (buffer[3] <= '4') &&
+ (buffer[4] == '\0'))
+ {
+ /* we found the entry in HKEY_LOCAL_MACHINE, now we need to */
+ /* find the corresponding entry under HKEY_DYN_DATA. */
+ /* add 5 to lm_path to skip over "Enum" and backslash */
+ search_dyn_data(dd_path, &lm_path[5], (buffer[3] - '1'));
+ }
+ }
+
+ index = 0;
+
+ do
+ {
+ size = 1023;
+
+ result = RegEnumKeyEx(
+ key,
+ index++,
+ buffer,
+ &size,
+ NULL,
+ NULL,
+ NULL,
+ &last_write);
+
+ if (result == ERROR_SUCCESS)
+ {
+ lm_path[length] = '\\';
+ lm_path[length + 1] = '\0';
+ strcpy(&lm_path[length + 1], buffer);
+
+ search_local_machine(lm_path, dd_path);
+
+ lm_path[length] = '\0';
+ }
+ }
+ while (result == ERROR_SUCCESS);
+
+ RegCloseKey(key);
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* GET_LPT_ADDRESSES_FROM_REGISTRY
+*
+* Searches Win95/98 registry recursively to get I/O port addresses for
+* parallel ports.
+*/
+void get_lpt_addresses_from_registry()
+{
+ char lm_path[1024];
+ char dd_path[1024];
+
+ strcpy(lm_path, "Enum");
+ strcpy(dd_path, "Config Manager");
+ search_local_machine(lm_path, dd_path);
+}
+#endif
+#endif
+
+void initialize_jtag_hardware()
+{
+ if (specified_com_port)
+ {
+ com_port = open(serial_port_name, O_RDWR);
+ if (com_port == -1)
+ {
+ fprintf(stderr, "Error: can't open serial port \"%s\"\n",
+ serial_port_name);
+ }
+ else
+ {
+ int i = 0, result = 0;
+ char data = 0;
+
+ data = 0x7e;
+ write(com_port, &data, 1);
+
+ for (i = 0; (i < 100) && (result != 1); ++i)
+ {
+ result = read(com_port, &data, 1);
+ }
+
+ if (result == 1)
+ {
+ data = 0x70; write(com_port, &data, 1); /* TDO echo off */
+ data = 0x72; write(com_port, &data, 1); /* auto LEDs off */
+ data = 0x74; write(com_port, &data, 1); /* ERROR LED off */
+ data = 0x76; write(com_port, &data, 1); /* DONE LED off */
+ data = 0x60; write(com_port, &data, 1); /* signals low */
+ }
+ else
+ {
+ fprintf(stderr, "Error: BitBlaster is not responding on %s\n",
+ serial_port_name);
+ close(com_port);
+ com_port = -1;
+ }
+ }
+ }
+ else
+ {
+#if PORT == WINDOWS || PORT == DOS
+
+#if PORT == WINDOWS
+ if (windows_nt)
+ {
+ initialize_nt_driver();
+ }
+ else
+ {
+#ifdef __BORLANDC__
+ fprintf(stderr, "Error: parallel port access is not available\n");
+#else
+ if (!specified_lpt_addr)
+ {
+ get_lpt_addresses_from_registry();
+
+ lpt_addr = 0;
+
+ if (specified_lpt_port)
+ {
+ lpt_addr = lpt_addresses_from_registry[lpt_port - 1];
+ }
+
+ if (lpt_addr == 0)
+ {
+ if (lpt_addresses_from_registry[3] != 0)
+ lpt_addr = lpt_addresses_from_registry[3];
+ if (lpt_addresses_from_registry[2] != 0)
+ lpt_addr = lpt_addresses_from_registry[2];
+ if (lpt_addresses_from_registry[1] != 0)
+ lpt_addr = lpt_addresses_from_registry[1];
+ if (lpt_addresses_from_registry[0] != 0)
+ lpt_addr = lpt_addresses_from_registry[0];
+ }
+
+ if (lpt_addr == 0)
+ {
+ if (specified_lpt_port)
+ {
+ lpt_addr = lpt_addr_table[lpt_port - 1];
+ }
+ else
+ {
+ lpt_addr = lpt_addr_table[0];
+ }
+ }
+ }
+ initial_lpt_ctrl = windows_nt ? 0x0c : read_byteblaster(2);
+#endif
+ }
+#endif
+
+#if PORT == DOS
+ /*
+ * Read word at specific memory address to get the LPT port address
+ */
+ WORD *bios_address = (WORD *) 0x00400008;
+
+ if (!specified_lpt_addr)
+ {
+ lpt_addr = bios_address[lpt_port - 1];
+
+ if ((lpt_addr != 0x278) &&
+ (lpt_addr != 0x27c) &&
+ (lpt_addr != 0x378) &&
+ (lpt_addr != 0x37c) &&
+ (lpt_addr != 0x3b8) &&
+ (lpt_addr != 0x3bc))
+ {
+ lpt_addr = lpt_addr_table[lpt_port - 1];
+ }
+ }
+ initial_lpt_ctrl = read_byteblaster(2);
+#endif
+
+ /* set AUTO-FEED low to enable ByteBlaster (value to port inverted) */
+ /* set DIRECTION low for data output from parallel port */
+ write_byteblaster(2, (initial_lpt_ctrl | 0x02) & 0xDF);
+#endif
+ }
+}
+
+void close_jtag_hardware()
+{
+ if (specified_com_port)
+ {
+ if (com_port != -1) close(com_port);
+ }
+ else
+ {
+#if PORT == WINDOWS || PORT == DOS
+ /* set AUTO-FEED high to disable ByteBlaster */
+ write_byteblaster(2, initial_lpt_ctrl & 0xfd);
+
+#if PORT == WINDOWS
+ if (windows_nt && (nt_device_handle != INVALID_HANDLE_VALUE))
+ {
+ if (port_io_count > 0) flush_ports();
+
+ CloseHandle(nt_device_handle);
+ }
+#endif
+#endif
+ }
+}
+
+#if PORT == WINDOWS
+/**************************************************************************/
+/* */
+
+BOOL initialize_nt_driver()
+
+/* */
+/* Uses CreateFile() to open a connection to the Windows NT device */
+/* driver. */
+/* */
+/**************************************************************************/
+{
+ BOOL status = FALSE;
+
+ ULONG buffer[1];
+ ULONG returned_length = 0;
+ char nt_lpt_str[] = { '\\', '\\', '.', '\\',
+ 'A', 'L', 'T', 'L', 'P', 'T', '1', '\0' };
+
+
+ nt_lpt_str[10] = (char) ('1' + (lpt_port - 1));
+
+ nt_device_handle = CreateFile(
+ nt_lpt_str,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (nt_device_handle == INVALID_HANDLE_VALUE)
+ {
+ fprintf(stderr,
+ "I/O error: cannot open device %s\nCheck port number and device driver installation",
+ nt_lpt_str);
+ }
+ else
+ {
+ if (DeviceIoControl(
+ nt_device_handle, /* Handle to device */
+ PGDC_IOCTL_GET_DEVICE_INFO_PP, /* IO Control code */
+ (ULONG *)NULL, /* Buffer to driver. */
+ 0, /* Length of buffer in bytes. */
+ &buffer, /* Buffer from driver. */
+ sizeof(ULONG), /* Length of buffer in bytes. */
+ &returned_length, /* Bytes placed in data_buffer. */
+ NULL)) /* Wait for operation to complete */
+ {
+ if (returned_length == sizeof(ULONG))
+ {
+ if (buffer[0] == PGDC_HDLC_NTDRIVER_VERSION)
+ {
+ status = TRUE;
+ }
+ else
+ {
+ fprintf(stderr,
+ "I/O error: device driver %s is not compatible\n(Driver version is %lu, expected version %lu.\n",
+ nt_lpt_str,
+ (unsigned long) buffer[0],
+ (unsigned long) PGDC_HDLC_NTDRIVER_VERSION);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "I/O error: device driver %s is not compatible.\n",
+ nt_lpt_str);
+ }
+ }
+
+ if (!status)
+ {
+ CloseHandle(nt_device_handle);
+ nt_device_handle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (!status)
+ {
+ /* error message already given */
+ exit(1);
+ }
+
+ return (status);
+}
+#endif
+
+#if PORT == WINDOWS || PORT == DOS
+/**************************************************************************/
+/* */
+
+void write_byteblaster
+(
+ int port,
+ int data
+)
+
+/* */
+/**************************************************************************/
+{
+#if PORT == WINDOWS
+ BOOL status = FALSE;
+
+ int returned_length = 0;
+ int buffer[2];
+
+
+ if (windows_nt)
+ {
+ /*
+ * On Windows NT, access hardware through device driver
+ */
+ if (port == 0)
+ {
+ port_io_buffer[port_io_count].data = (USHORT) data;
+ port_io_buffer[port_io_count].command = PGDC_WRITE_PORT;
+ ++port_io_count;
+
+ if (port_io_count >= PORT_IO_BUFFER_SIZE) flush_ports();
+ }
+ else
+ {
+ if (port_io_count > 0) flush_ports();
+
+ buffer[0] = port;
+ buffer[1] = data;
+
+ status = DeviceIoControl(
+ nt_device_handle, /* Handle to device */
+ PGDC_IOCTL_WRITE_PORT_PP, /* IO Control code for write */
+ (ULONG *)&buffer, /* Buffer to driver. */
+ 2 * sizeof(int), /* Length of buffer in bytes. */
+ (ULONG *)NULL, /* Buffer from driver. Not used. */
+ 0, /* Length of buffer in bytes. */
+ (ULONG *)&returned_length, /* Bytes returned. Should be zero. */
+ NULL); /* Wait for operation to complete */
+
+ if ((!status) || (returned_length != 0))
+ {
+ fprintf(stderr, "I/O error: Cannot access ByteBlaster hardware\n");
+ CloseHandle(nt_device_handle);
+ exit(1);
+ }
+ }
+ }
+ else
+#endif
+ {
+ /*
+ * On Windows 95, access hardware directly
+ */
+ outp((WORD)(port + lpt_addr), (WORD)data);
+ }
+}
+
+/**************************************************************************/
+/* */
+
+int read_byteblaster
+(
+ int port
+)
+
+/* */
+/**************************************************************************/
+{
+ int data = 0;
+
+#if PORT == WINDOWS
+
+ BOOL status = FALSE;
+
+ int returned_length = 0;
+
+
+ if (windows_nt)
+ {
+ /* flush output cache buffer before reading from device */
+ if (port_io_count > 0) flush_ports();
+
+ /*
+ * On Windows NT, access hardware through device driver
+ */
+ status = DeviceIoControl(
+ nt_device_handle, /* Handle to device */
+ PGDC_IOCTL_READ_PORT_PP, /* IO Control code for Read */
+ (ULONG *)&port, /* Buffer to driver. */
+ sizeof(int), /* Length of buffer in bytes. */
+ (ULONG *)&data, /* Buffer from driver. */
+ sizeof(int), /* Length of buffer in bytes. */
+ (ULONG *)&returned_length, /* Bytes placed in data_buffer. */
+ NULL); /* Wait for operation to complete */
+
+ if ((!status) || (returned_length != sizeof(int)))
+ {
+ fprintf(stderr, "I/O error: Cannot access ByteBlaster hardware\n");
+ CloseHandle(nt_device_handle);
+ exit(1);
+ }
+ }
+ else
+#endif
+ {
+ /*
+ * On Windows 95, access hardware directly
+ */
+ data = inp((WORD)(port + lpt_addr));
+ }
+
+ return (data & 0xff);
+}
+
+#if PORT == WINDOWS
+void flush_ports(void)
+{
+ ULONG n_writes = 0L;
+ BOOL status;
+
+ status = DeviceIoControl(
+ nt_device_handle, /* handle to device */
+ PGDC_IOCTL_PROCESS_LIST_PP, /* IO control code */
+ (LPVOID)port_io_buffer, /* IN buffer (list buffer) */
+ port_io_count * sizeof(struct PORT_IO_LIST_STRUCT),/* length of IN buffer in bytes */
+ (LPVOID)port_io_buffer, /* OUT buffer (list buffer) */
+ port_io_count * sizeof(struct PORT_IO_LIST_STRUCT),/* length of OUT buffer in bytes */
+ &n_writes, /* number of writes performed */
+ 0); /* wait for operation to complete */
+
+ if ((!status) || ((port_io_count * sizeof(struct PORT_IO_LIST_STRUCT)) != n_writes))
+ {
+ fprintf(stderr, "I/O error: Cannot access ByteBlaster hardware\n");
+ CloseHandle(nt_device_handle);
+ exit(1);
+ }
+
+ port_io_count = 0;
+}
+#endif /* PORT == WINDOWS */
+#endif /* PORT == WINDOWS || PORT == DOS */
+
+#if !defined (DEBUG)
+#pragma optimize ("ceglt", off)
+#endif
+
+void delay_loop(long count)
+{
+ while (count != 0L) count--;
+}
diff --git a/common/recipes-utils/jbi/files/make/Microsoft/nmake.mak b/common/recipes-utils/jbi/files/make/Microsoft/nmake.mak
new file mode 100644
index 0000000..352a9c5
--- /dev/null
+++ b/common/recipes-utils/jbi/files/make/Microsoft/nmake.mak
@@ -0,0 +1,65 @@
+#
+# Module: makefile
+#
+# Copyright (C) Altera Corporation 1998-2001
+#
+# Description: Makefile for JAM Bytecode Player
+#
+
+OBJS = \
+ jbistub.obj \
+ jbimain.obj \
+ jbicomp.obj \
+ jbijtag.obj
+
+
+!IF "$(MEM_TRACKER)" != ""
+!IF "$(STATIC_MEMORY_SIZE)" != ""
+# MEMORY TRACKER ON, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj::
+ cl /W4 /c /O2 /ML /DWINNT /DMEM_TRACKER /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+!ELSE
+# MEMORY TRACKER ON, USE DYNAMIC MEMORY
+.c.obj::
+ cl /W4 /c /O2 /ML /DWINNT /DMEM_TRACKER $<
+!ENDIF
+!ELSE
+!IF "$(STATIC_MEMORY_SIZE)" != ""
+# MEMORY TRACKER OFF, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj::
+ cl /W4 /c /O2 /ML /DWINNT /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+!ELSE
+# MEMORY TRACKER OFF, USE DYNAMIC MEMORY
+.c.obj::
+ cl /W4 /c /O2 /ML /DWINNT $<
+!ENDIF
+!ENDIF
+
+jbi.exe : $(OBJS)
+ link $(OBJS) advapi32.lib /out:jbi.exe
+
+# Dependencies:
+
+jbistub.obj : \
+ jbistub.c \
+ jbiport.h \
+ jbiexprt.h
+
+jbimain.obj : \
+ jbimain.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h \
+ jbicomp.h
+
+jamcomp.obj : \
+ jamcomp.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbicomp.h
+
+jbijtag.obj : \
+ jbijtag.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h
diff --git a/common/recipes-utils/jbi/files/make/PCVS/PVCS16.MAK b/common/recipes-utils/jbi/files/make/PCVS/PVCS16.MAK
new file mode 100644
index 0000000..e943aa4
--- /dev/null
+++ b/common/recipes-utils/jbi/files/make/PCVS/PVCS16.MAK
@@ -0,0 +1,61 @@
+#
+# Module: makefile
+#
+# Copyright (C) Altera Corporation 1998-2001
+#
+# Description: Makefile for JAM Bytecode Player
+#
+
+OBJS = \
+ jbistub.obj \
+ jbimain.obj \
+ jbicomp.obj \
+ jbijtag.obj
+
+
+%if "$(MEM_TRACKER)" && "$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER ON, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj :
+ cl /W4 /AL /c /O2 /Zp1 /DPORT=DOS /DMEM_TRACKER /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+%elseif "$(MEM_TRACKER)" && !"$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER ON, USE DYNAMIC MEMORY
+.c.obj :
+ cl /W4 /AL /c /O2 /Zp1 /DPORT=DOS /DMEM_TRACKER $<
+%elseif !"$(MEM_TRACKER)" && "$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER OFF, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj :
+ cl /W4 /AL /c /O2 /Zp1 /DPORT=DOS /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+%else !"$(MEM_TRACKER)" && !"$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER OFF, USE DYNAMIC MEMORY
+.c.obj :
+ cl /W4 /AL /c /O2 /Zp1 /DPORT=DOS $<
+%endif
+
+jbi.exe : $(OBJS)
+ link /STACK:0x8000 $(OBJS), jbi.exe,,,,
+
+# Dependencies:
+
+jbistub.obj : \
+ jbistub.c \
+ jbiport.h \
+ jbiexprt.h
+
+jbimain.obj : \
+ jbimain.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h \
+ jbicomp.h
+
+jamcomp.obj : \
+ jamcomp.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbicomp.h
+
+jbijtag.obj : \
+ jbijtag.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h
diff --git a/common/recipes-utils/jbi/files/make/PCVS/pvcs32.mak b/common/recipes-utils/jbi/files/make/PCVS/pvcs32.mak
new file mode 100644
index 0000000..409ef47
--- /dev/null
+++ b/common/recipes-utils/jbi/files/make/PCVS/pvcs32.mak
@@ -0,0 +1,61 @@
+#
+# Module: makefile
+#
+# Copyright (C) Altera Corporation 1998-2001
+#
+# Description: Makefile for JAM Bytecode Player
+#
+
+OBJS = \
+ jbistub.obj \
+ jbimain.obj \
+ jbicomp.obj \
+ jbijtag.obj
+
+
+%if "$(MEM_TRACKER)" && "$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER ON, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj :
+ cl /W4 /c /O2 /ML /DWINNT /DMEM_TRACKER /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+%elseif "$(MEM_TRACKER)" && !"$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER ON, USE DYNAMIC MEMORY
+.c.obj :
+ cl /W4 /c /O2 /ML /DWINNT /DMEM_TRACKER $<
+%elseif !"$(MEM_TRACKER)" && "$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER OFF, USE 'STATIC_MEMORY_SIZE' KB OF STATIC MEMORY
+.c.obj :
+ cl /W4 /c /O2 /ML /DWINNT /DUSE_STATIC_MEMORY=$(STATIC_MEMORY_SIZE) $<
+%else !"$(MEM_TRACKER)" && !"$(STATIC_MEMORY_SIZE)"
+# MEMORY TRACKER OFF, USE DYNAMIC MEMORY
+.c.obj :
+ cl /W4 /c /O2 /ML /DWINNT $<
+%endif
+
+jbi.exe : $(OBJS)
+ link $(OBJS) advapi32.lib /out:jbi.exe
+
+# Dependencies:
+
+jbistub.obj : \
+ jbistub.c \
+ jbiport.h \
+ jbiexprt.h
+
+jbimain.obj : \
+ jbimain.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h \
+ jbicomp.h
+
+jamcomp.obj : \
+ jamcomp.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbicomp.h
+
+jbijtag.obj : \
+ jbijtag.c \
+ jbiport.h \
+ jbiexprt.h \
+ jbijtag.h
diff --git a/common/recipes-utils/jbi/files/readme.openbmc b/common/recipes-utils/jbi/files/readme.openbmc
new file mode 100644
index 0000000..f8620f7
--- /dev/null
+++ b/common/recipes-utils/jbi/files/readme.openbmc
@@ -0,0 +1,5 @@
+Changeset from the original jdi_22.exe
+
+1. removed all files in 'exe/'
+2. renamed all files in 'code' to lower case
+3. converted all files in 'code' from DOS style to UNIX style \ No newline at end of file
diff --git a/common/recipes-utils/jbi/files/readme.txt b/common/recipes-utils/jbi/files/readme.txt
new file mode 100644
index 0000000..813d88d
--- /dev/null
+++ b/common/recipes-utils/jbi/files/readme.txt
@@ -0,0 +1,464 @@
+********************************************************************************************
+ Jam STAPL Byte-Code Player Version 2.2 README 7/15/2002
+********************************************************************************************
+
+CONTENTS
+
+A. DESCRIPTION
+B. INCLUDED IN THIS RELEASE
+C. NEW IN VERSION 2.2
+D. RUNNING THE PLAYER IN COMMAND-LINE MODE
+E. PORTING THE JAM STAPL BYTE-CODE PLAYER
+F. JAM STAPL BYTE-CODE PLAYER API
+G. MEMORY USAGE
+H. SUPPORT
+
+A. DESCRIPTION
+--------------
+The Jam STAPL Byte-Code Player is a software driver that allows test and programming algorithms
+for IEEE 1149.1 Joint Test Action Group (JTAG)-compliant devices to be asserted via the
+JTAG port. The Jam STAPL Byte-Code Player reads and decodes information in Jam STAPL
+Byte-Code Files (.jbc) to program and test programmable logic devices (PLDs), memories,
+and other devices in a JTAG chain. The Jam STAPL Byte-Code Player complies with STAPL
+(Standard Test and Programming Language) Specification JESD-71. The construction of the
+Player permits fast programming times, small programming files, and easy in-field upgrades.
+Upgrades are simplified, because all programming/test algorithms and data are confined to the
+Jam STAPL Byte-Code File. Version 2.2 supports Jam STAPL Byte-Code Files (.jbc) that have been
+compiled using the Jam STAPL Byte-Code Compiler. The Player is also able to read and "play"
+older Jam Byte-Code files based on Jam v1.1 syntax.
+ The .jbc File is a binary version of the ASCII Jam File (.jam). The Jam STAPL Byte-Code
+format consists, among other things, of a "byte code" representation of Jam commands, as
+they are defined in STAPL Specification JESD-71. This means that the .jbc File is simply a
+different implementation of the .jam file. This binary implementation results in smaller
+file sizes and shorter programming times.
+ This document should be used together with AN 122 (Using STAPL for ISP & ICR via
+an Embedded Processor).
+
+B. INCLUDED IN THIS RELEASE
+---------------------------
+The following tables provide the directory structure of the files on this CD-ROM:
+
+Directory Filename Description
+--------- -------- -----------------------
+\exe \16-bit-DOS\jbi16.exe Supports the BitBlaster serial,
+ ByteBlaster parallel, Xilinx
+ Parallel Download Cable III, and
+ Lattice ispDOWNLOAD cables for
+ PCs running 16-bit DOS platforms.
+
+ \Win9598-WinNT\jbi32.exe Supports the BitBlaster serial
+ ByteBlaster parallel, Xilinx
+ Parallel Download Cable III, and
+ Lattice ispDOWNLOAD cables for
+ PCs running 32-bit Windows
+ (Windows 95, Windows 98 and Windows NT)
+
+
+Directory Filename Description
+--------- -------- ------------------------------------------
+\code jbicomp.h Source code for the Jam STAPL Byte-Code Player
+ jbiexprt.h
+ jbijtag.h
+ jbiport.h
+ jbicomp.c
+ jbijtag.c
+ jbimain.c
+ jbistub.c
+
+Directory Filename Description
+--------- -------- ------------------------------------------
+\make \microsoft\makefile.mak Make file compatible with Microsoft Visual
+ C++ compiler v5.0. Builds a 32-bit windows
+ console executable.
+
+\make \pvcs\pvcs32.mak Builds a 32-bit executable.
+
+\make \pvcs\pvcs16.mak Builds a 16-bit executable.
+
+
+C. NEW IN VERSION 2.2
+---------------------
+Updates in the Jam STAPL Byte-Code Player version 2.2 include:
+
+* fixed /W4 warnings
+* updated JTAG state transition paths
+
+
+D. RUNNING THE JAM STAPL BYTE-CODE PLAYER IN COMMAND-LINE MODE
+--------------------------------------------------------------
+If the Player is going to be run on a PC or a workstation, the following commands can be
+used to execute programming or other tasks:
+
+Jam STAPL Byte-Code Player Version 2.2
+Copyright (C) 1998-2000 Altera Corporation
+
+Usage: jbi [options] <filename>
+
+Available options:
+ -h : show help message
+ -v : show verbose messages
+ -i : show file info only - do not execute
+ -a<action> : specify action name (Jam STAPL)
+ -d<var=val> : initialize variable to specified value (Jam 1.1)
+ -d<proc=1> : enable optional procedure (Jam STAPL)
+ -d<proc=0> : disable recommended procedure (Jam STAPL)
+ -p<port> : parallel port number or address (for ByteBlaster)
+ -c<cable> : alternative download cable compatibility: -cl or -cx
+ -s<port> : serial port name (for BitBlaster)
+ -r : don't reset JTAG TAP after use
+
+Command line text is not case-sensitive.
+
+Use the -a flag when applying Jam STAPL Byte-Code files. Use the -d flag when applying Jam v1.1
+Byte-Code files.
+
+Valid action names, as specified by JEDEC Standard JESD-71 are:
+
+ Action Name Description
+ ----------- -----------
+ CHECKCHAIN Verify the continuity of the IEEE 1149.1 JTAG scan chain
+ READ_IDCODE Read the IEEE 1149.1 IDCODE and EXPORT it (print it)
+ READ_USERCODE Read the IEEE 1149.1 USERCODE and EXPORT it (print it)
+ READ_UES Read the IEEE 1149.1 UESCODE and EXPORT it (print it)
+ ERASE Perform a bulk erase of the device(s)
+ BLANKCHECK Check the erased state of the device(s)
+ PROGRAM Program the device
+ VERIFY Verify the programming data of the device(s)
+ READ Read the programming data of the device(s)
+ CHECKSUM Calculate one fuse checksum of the programming data of the device(s)
+ SECURE Set the security bit of the device(s)
+ QUERY_SECURITY Check whether the security bit is set
+ TEST Perform a test. This test can include tests such as boundary-scan,
+ internal, vector, and built-in self tests
+
+Valid initialization variables and values for the -d flag are:
+
+ Initialization String Value Action
+ --------------------- ----- ------
+ DO_PROGRAM 0 Do not program the device
+ DO_PROGRAM 1 Program the device
+ DO_VERIFY 0 Do not verify the device
+ DO_VERIFY 1 Verify the device
+ DO_BLANKCHECK 0 Do not check the erased state of the device
+ DO_BLANKCHECK 1 Check the erased state of the device
+ READ_UESCODE 0 Do not read the JTAG UESCODE
+ READ_UESCODE 1 Read UESCODE and export it
+ DO_SECURE 0 Do not set the security bit
+ DO_SECURE 1 Set the security bit
+
+
+E. PORTING THE JAM STAPL BYTE-CODE PLAYER
+-----------------------------------------
+The Jam STAPL Byte-Code Player is designed to be easily ported to any processor-based hardware
+system. All platform-specific code is placed in the jbistub.c and jbimain.c files. Routines
+that perform any interaction with the outside world are confined to the jbistub.c source
+file. Preprocessor statements encase operating system-specific code and code pertaining to
+specific hardware. All changes to the source code for porting are mostly confined to the
+jbistub.c file and in some cases porting the Jam Player is as simple as changing a
+single #define statement. This process also makes debugging simple. For example, if
+the jbistub.c file has been customized for a particular embedded application, but is
+not working, the equivalent DOS Jam STAPL Byte-Code Player and a download cable can be used to
+check the hardware continuity and provide a "known good" starting point from which to attack
+the problem.
+
+The jbistub.c and jbimain.c files in this release target the DOS operating system, by default.
+To change the targeted platform, edit the following line in the jbistub.c and jbimain.c files:
+
+ #define PORT DOS
+
+The preprocessor statement takes the form:
+
+ #define PORT [PLATFORM]
+
+Change the [PLATFORM] field to one of the supported platforms: EMBEDDED, DOS, WINDOWS,
+or UNIX. The following table explains how to port the Jam STAPL Byte-Code Player for each of the
+supported platforms:
+
+PLATFORM COMPILER ACTIONS
+-------- -------- ---------------------------------------------
+EMBEDDED 16 or 32-bit Change #define and see EMBEDDED PLATFORM below
+DOS 16-bit Change #define and compile
+WINDOWS 32-bit Change #define and compile
+UNIX 32-bit Change #define and compile
+
+The source code supplied in this release is ANSI C source. In cases where a different
+download cable or other hardware is used, the DOS, WINDOWS, and UNIX platforms will require
+additional code customization, which is described below.
+
+EMBEDDED PLATFORM
+Because there are many different kinds of embedded systems, each with different hardware and
+software requirements, some additional customization must be done to port the Jam STAPL
+Byte-Code Player for embedded systems. To port the Player, the following functions may
+need to be customized:
+
+FUNCTION DESCRIPTION
+--------- ------------------------------------------------------------------
+jbi_jtag_io() Interface to the IEEE 1149.1 JTAG signals, TDI, TMS, TCK, and TDO.
+jbi_message() Prints information and error text to standard output, when available.
+jbi_export() Passes information such as the User Electronic Signature (UES) back to the
+ calling program.
+jbi_delay() Implements the programming pulses or delays needed during execution.
+
+Miscellaneous
+jbi_vector_map() Processes signal-to-pin map for non-IEEE 1149.1 JTAG signals.
+jbi_vector_io() Asserts non-IEEE 1149.1 JTAG signals as defined in the VECTOR MAP.
+
+jbi_jtag_io()
+-------------
+int jbi_jtag_io(int tms, int tdi, int read_tdo)
+
+This function provides exclusive access to the IEEE 1149.1 JTAG signals. You must always
+customize this function to write to the proper hardware port.
+
+The code in this release supports a serial mode specific to the Altera BitBlaster download
+cable. If a serial interface is required, this code can be customized for that purpose.
+However, this customization would require some additional processing external to the
+embedded processor to turn the serial data stream into valid JTAG vectors. This readme file
+does not discuss customization of serial mode. Contact Altera Applications at (800) 800-EPLD
+for more information.
+
+In most cases a parallel byte mode is used. When in byte mode, jbi_jtag_io() is passed
+the values of TMS and TDI. Likewise, the variable read_tdo tells the function whether
+reading TDO is required. (Because TCK is a clock and is always written, it is written
+implicitly within the function.) If requested, jbi_jtag_io() returns the value of TDO read.
+Sample code is shown below:
+
+int jbi_jtag_io(int tms, int tdi, int read_tdo)
+{
+ int data = 0;
+ int tdo = 0;
+
+ if (!jtag_hardware_initialized)
+ {
+ initialize_jtag_hardware();
+ jtag_hardware_initialized = TRUE;
+ }
+
+ data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0));
+
+ write_byteblaster(0, data);
+
+ if (read_tdo)
+ {
+ tdo = (read_byteblaster(1) & 0x80) ? 0 : 1;
+ }
+
+ write_byteblaster(0, data | 0x01);
+
+ write_byteblaster(0, data);
+
+ return (tdo);
+}
+
+The code, as shown above, is configured to read/write to a PC parallel port.
+initialize_jtag_hardware() sets the control register of the port for byte mode. As shown
+above, jbi_jtag_io() reads and writes to the port as follows:
+
+|---------------------------------------------------------------|
+| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | I/O Port
+|---------------------------------------------------------------|
+| 0 | TDI | 0 | 0 | 0 | 0 | TMS | TCK | OUTPUT DATA - Base Address
+|---------------------------------------------------------------|
+| !TDO | X | X | X | X | --- | --- | --- | INPUT DATA - Base Address + 1
+|---------------------------------------------------------------|
+
+The PC parallel port inverts the actual value of TDO. Thus, jbi_jtag_io() inverts
+it again to retrieve the original data. Inverted:
+
+ tdo = (read_byteblaster(1) & 0x80) ? 0 : 1;
+
+If the target processor does not invert TDO, the code should look like:
+
+ tdo = (read_byteblaster(1) & 0x80) ? 1 : 0;
+
+To map the signals to the correct addresses simply use the left shift (<<) or right shift
+(>>) operators. For example, if TMS and TDI are at ports 2 and 3, respectively, then the
+code would be as shown below:
+
+ data = (((tdi ? 0x40 : 0)>>3) | ((tms ? 0x02 : 0)<<1));
+
+The same process applies to TCK and TDO.
+
+read_byteblaster() and write_byteblaster() use the inp() and outp() <conio.h> functions,
+respectively, to read and write to the port. If these functions are not available,
+equivalent functions should be substituted.
+
+jbi_message()
+--------------
+void jam_message(char *message_text)
+
+When the Jam STAPL Byte-Code Player encounters a PRINT command within the .jbc File, it processes
+the message text and passes it to jbi_message(). The text is sent to stdio. If a standard
+output device is not available, jbi_message() does nothing and returns. The Jam STAPL
+Byte-Code Player does not append a newline character to the end of the text message.
+This function should append a newline character for those systems that require one.
+
+jbi_export()
+------------
+void jbi_export(char *key, long value)
+
+The jbi_export() function sends information to the calling program in the form of a text
+string and associated integer value. The text string is called the key string and it
+determines the significance and interpretation of the integer value. An example use of this
+function would be to report the device USERCODE back to the calling program.
+
+jbi_delay()
+-----------
+void jbi_delay(long microseconds)
+
+jbi_delay() is used to implement programming pulse widths necessary for programming PLDs,
+memories, and configuring SRAM-based devices. These delays are implemented using software
+loops calibrated to the speed of the targeted embedded processor. The Jam STAPL Byte-Code
+Player is told how long to delay with the .jbc File WAIT command. This function can be
+customized easily to measure the passage of time via a hardware-based timer. jbi_delay()
+must perform accurately over the range of one millisecond to one second. The function can
+take as much as 10% more time than is specified, but cannot return in less time. To minimize
+the time to execute the Jam statements, it is generally recommended to calibrate the delay as
+accurately as possible.
+
+Miscellaneous Functions
+------------------------
+jbi_vector_map() and jbi_vector_io()
+
+The VMAP and VECTOR Jam commands are translated by these functions to assert signals to
+non-JTAG ports. Altera .jbc Files do not use these commands. If the Jam STAPL Byte-Code Player
+will be used only to program Altera devices, these routines can be removed. In the event
+that the Jam Player does encounter the VMAP and VECTOR commands, it will process the
+information so that non-JTAG signals can be written and read as defined by JEDEC Specification
+JESD-71.
+
+jbi_malloc()
+
+void *jam_malloc(unsigned int size)
+
+During execution, the Jam STAPL Byte-Code Player will allocate memory to perform its tasks. When
+it allocates memory, it calls the jbi_malloc() function. If malloc() is not available to the
+embedded system it must be replaced with an equivalent function.
+
+jbi_free()
+
+void jbi_free(void *ptr)
+
+This function is called when the Jam STAPL Byte-Code Player frees memory. If free() is not
+available to the embedded system, it must be replaced with an equivalent function.
+
+F. JAM STAPL Byte-Code Player API
+---------------------------------
+The main entry point for the Jam Player is the jbi_execute function:
+
+JAM_RETURN_TYPE jbi_execute
+(
+ PROGRAM_PTR program,
+ long program_size,
+ char *workspace,
+ long workspace_size,
+ char *action,
+ char **init_list,
+ long *error_line,
+ int *exit_code,
+ int *format_version
+)
+
+This routine recieves 6 parameters, passes back 2 parameters, and returns a status
+code (of JAM_RETURN_TYPE). This function is called once in main(), which is coded in the
+jbistub.c file (jbi_execute() is defined in the jbimain.c file). Some processing is done in
+main() to check for valid data being passed to jbi_execute(), and to set up some of the
+buffering required to store the .jbc File.
+
+The program parameter is a pointer to the memory location where the .jbc File is stored
+(memory space previously malloc'd and assigned in main()). jbi_execute() assigns this
+pointer to the global variable jbi_program, which provides the rest of the Jam STAPL
+Byte-Code Player with access to the .jbc File via the GET_BYTE, GET_WORD, and
+GET_DWORD macros.
+
+program_size provides the number of bytes stored in the memory buffer occupied
+by the .jbc File.
+
+workspace points to memory previously allocated in main(). This space is the sum of all
+memory reserved for all of the processing that the Jam STAPL Byte-Code Player must do, including
+the space taken by the .jbc File. Memory is only used in this way when the Jam STAPL Byte-Code
+Player is executed using the -m console option. If the -m option is not used, the Jam Byte
+Code Player is free to allocate memory dynamically as it is needed. In this case, workspace
+points to NULL. jbi_execute() assigns the workspace pointer to the global variable,
+jbi_workspace, giving the rest of the Jam STAPL Byte-Code Player access to this block of memory.
+
+workspace_size provides the size of the workspace in bytes. If the workspace pointer points
+to NULL this parameter is ignored. jbi_execute() assigns workspace_size to the global
+variable, jbi_workspace_size.
+
+action is the way the Player is told what function should be performed, as defined
+by STAPL. (i.e. PROGRAM, READ_USERCODE, etc) The action pointer points to the string
+that tells the Player what functions to execute within the .jbc file. Each action can
+contain "recommended" and "optional" sub-actions. "Recommended" sub-actions are those
+that will be executed by default, while "optional" sub-actions will be skipped.
+For example, passing "PROGRAM\0" will result in the following steps for an Altera .jbc
+file:
+ - ERASE (recommended)
+ - BLANKCHECK (optional)
+ - PROGRAM (recommended)
+ - VERIFY (recommended)
+
+So, by simply passing "PROGRAM\0" the device will be programmed and verified. This is the
+action Altera recommends using with it's .jbc files. If you want to add the BLANKCHECK step
+you must pass "DO_BLANKCHECK=1\0" via the init_list pointer. See Section D for other valid
+action strings. Note that the action string must be NULL terminated.
+
+init_list is a parameter that is used when applying pre-JEDEC, Jam v1.1 .jbc files, or when
+overriding optional sub-actions, as in the example above. While older pre-JEDEC .jbc files
+can be played, it is strongly recommended that STAPL-based .jbc files be used. When using
+STAPL-based .jbc files, init_list should point to NULL. If an older .jbc file must be used,
+see AN 88 for more details on the parameters that init_list can point to.
+
+If an error occurs during execution of the .jbc File, error_line provides the
+line number of the .jbc File where the error occured. This error is associated
+with the function of the device, as opposed to a syntax or software error in the .jbc File.
+
+exit_code provides general information about the nature of an error associated with a
+malfunction of the device or a functional error:
+
+ exit_code Description
+ --------- -----------
+ 0 Success
+ 1 Checking chain failure
+ 2 Reading IDCODE failure
+ 3 Reading USERCODE failure
+ 4 Reading UESCODE failure
+ 5 Entering ISP failure
+ 6 Unrecognized device
+ 7 Device version is not supported
+ 8 Erase failure
+ 9 Device is not blank
+ 10 Device programming failure
+ 11 Device verify failure
+ 12 Read failure
+ 13 Calculating checksum failure
+ 14 Setting security bit failure
+ 15 Querying security bit failure
+ 16 Exiting ISP failure
+ 17 Performing system test failure
+
+These codes are intended to provide general information about the nature of the failure.
+Additional analysis would need to be done to determine the root cause of any one of these
+errors. In most cases, if there is any device-related problem or hardware continuity
+problem, the "Unrecognized device" error will be issued. In this case, first take the
+steps outlined in Section D for debugging the Jam Player. If debugging is unsuccessful,
+contact Altera for support.
+
+If the "Device version is not supported" error is issued, it is most likely due to a
+.jbc File that is older than the current device revision. Always use the latest version of
+MAX+PLUS II to generate the .jbc File. For more support, see Section G.
+
+jbi_execute() returns with a code indicating the success or failure of the execution. This
+code is confined to errors associated with the syntax and structural accuracy of the .jbc
+File. These codes are defined in the jbistub.c file, where the array variable "error_text[]".
+
+format_version should be set equal to "2" when calling jbi_execute. This means that the
+Player will expect a STAPL-based .jbc file.
+
+G. MEMORY USAGE
+Memory usage is documented in detail in AN 122 (Using the Jam Language for ISP via an
+Embedded Processor).
+
+H. SUPPORT
+For additional support, submit a Service Request at http://www.altera.com/mysupport. Bugs or
+suggested enhancements can also be communicated via this channel. \ No newline at end of file
diff --git a/common/recipes-utils/jbi/jbi_2.2.bb b/common/recipes-utils/jbi/jbi_2.2.bb
new file mode 100644
index 0000000..947dbac
--- /dev/null
+++ b/common/recipes-utils/jbi/jbi_2.2.bb
@@ -0,0 +1,41 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "ALTERA Jam STAPL Byte-Code Player"
+SECTION = "utils"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
+
+SRC_URI = "file://code \
+ "
+
+S = "${WORKDIR}/code"
+
+DEPENDS += "liblog libgpio"
+
+do_install() {
+ bin="${D}/usr/local/bin"
+ install -d ${bin}
+ install -m 755 jbi ${bin}/jbi
+}
+
+FILES_${PN} = "/usr/local/bin"
+
+FILES_${PN}-dbg += "/usr/local/bin/.debug"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/common/recipes-utils/openbmc-gpio/files/COPYING b/common/recipes-utils/openbmc-gpio/files/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/common/recipes-utils/openbmc-gpio/files/board_gpio_table.py b/common/recipes-utils/openbmc-gpio/files/board_gpio_table.py
new file mode 100644
index 0000000..3261f51
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/board_gpio_table.py
@@ -0,0 +1,23 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+# This is an dummy board GPIO table. If this is included in the final image,
+# please double check the configuration of your image to define the correct
+# GPIO table to be used for your board.
+
+board_gpio_table = [
+]
diff --git a/common/recipes-utils/openbmc-gpio/files/openbmc_gpio.py b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio.py
new file mode 100644
index 0000000..9e92324
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio.py
@@ -0,0 +1,164 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import logging
+import os
+import string
+
+
+_gpio_shadow = '/tmp/gpionames'
+
+
+def setup_shadow(shadow=None):
+ global _gpio_shadow
+ if shadow is not None:
+ _gpio_shadow = shadow
+ if not os.path.exists(_gpio_shadow):
+ os.makedirs(_gpio_shadow)
+
+
+def gpio_name2value(name):
+ name = str(name).lower()
+ if name.startswith('gpio'):
+ name = name[4:]
+ try:
+ return int(name)
+ except:
+ # it is not just value, try treat it as name like 'A0'
+ pass
+ val = 0
+ try:
+ if len(name) != 2 and len(name) != 3:
+ raise
+ for idx in range(0, len(name)):
+ ch = name[idx]
+ if ch in string.ascii_lowercase:
+ # letter cannot be the last character
+ if idx == len(name) - 1:
+ raise
+ tmp = ord(ch) - ord('a') + 1
+ val = val * 26 + tmp
+ elif ch in string.digits:
+ # digit must be the last character
+ if idx != len(name) - 1:
+ raise
+ # the digit must be 0-7
+ tmp = ord(ch) - ord('0')
+ if tmp > 7:
+ raise
+ # 'A4' is value 4
+ if val > 0:
+ val -= 1
+ val = val * 8 + tmp
+ else:
+ raise
+ except:
+ logging.exception('Invalid GPIO name "%s"' % name)
+ return val
+
+
+def gpio_dir(name, check_shadow=True):
+ GPIODIR_FMT = '/sys/class/gpio/gpio{gpio}'
+ if check_shadow:
+ shadowdir = os.path.join(_gpio_shadow, name)
+ if os.path.isdir(shadowdir):
+ return shadowdir
+ val = gpio_name2value(name)
+ return GPIODIR_FMT.format(gpio=val)
+
+
+def gpio_get_shadow(name):
+ path = gpio_dir(name, check_shadow=False)
+ for child in os.listdir(_gpio_shadow):
+ try:
+ child = os.path.join(_gpio_shadow, child)
+ if os.readlink(child) == path:
+ return child
+ except:
+ pass
+ return None
+
+
+def gpio_export(name, shadow=None):
+ GPIOEXPORT = '/sys/class/gpio/export'
+ if shadow is not None or shadow != '':
+ shadowdir = os.path.join(_gpio_shadow, shadow)
+ if os.path.exists(shadowdir):
+ raise Exception('Shadow "%s" exists already' % shadowdir)
+ old_shadow = gpio_get_shadow(name)
+ if old_shadow is not None:
+ raise Exception('Shadow "%s" already exists for %s'
+ % (old_shadow, name))
+
+ val = gpio_name2value(name)
+ try:
+ with open(GPIOEXPORT, 'w') as f:
+ f.write('%d\n' % val)
+ except:
+ # in case the GPIO has been exported already
+ pass
+ if shadow is not None:
+ gpiodir = gpio_dir(val, check_shadow=False)
+ os.symlink(gpiodir, shadowdir)
+
+
+def gpio_get(name, change_direction=True):
+ path = gpio_dir(name)
+ if change_direction:
+ with open(os.path.join(path, 'direction'), 'w') as f:
+ f.write('in\n')
+ with open(os.path.join(path, 'value'), 'r') as f:
+ val = int(f.read().rstrip('\n'))
+ return val
+
+
+def gpio_set(name, value, change_direction=True):
+ path = gpio_dir(name)
+ with open(os.path.join(path, 'value'), 'w') as f:
+ f.write('%d\n' % (1 if value else 0))
+ if change_direction:
+ with open(os.path.join(path, 'direction'), 'w') as f:
+ f.write('out\n')
+
+
+def gpio_info(name):
+ res = {}
+ # first check if name is shadow
+ path = None
+ shadow = os.path.join(_gpio_shadow, name)
+ if os.path.exists(shadow):
+ if not os.path.islink(shadow) or not os.path.isdir(shadow):
+ raise Exception('Path "%s" is not a valid shadow path' % shadow)
+ path = os.readlink(shadow)
+ else:
+ path = gpio_dir(name, check_shadow=False)
+ shadow = gpio_get_shadow(name)
+ res['path'] = path
+ res['shadow'] = shadow
+ if os.path.isdir(path):
+ with open(os.path.join(path, 'direction'), 'r') as f:
+ res['direction'] = f.read().rstrip('\n')
+ with open(os.path.join(path, 'value'), 'r') as f:
+ res['value'] = int(f.read().rstrip('\n'))
+ else:
+ res['direction'] = None
+ res['value'] = None
+ return res
diff --git a/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_setup.py b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_setup.py
new file mode 100644
index 0000000..7c126d9
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_setup.py
@@ -0,0 +1,76 @@
+#!/usr/bin/python -tt
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from board_gpio_table import board_gpio_table
+from soc_gpio_table import soc_gpio_table
+
+import openbmc_gpio
+import openbmc_gpio_table
+
+import logging
+import sys
+
+
+def setup_board_gpio(soc_gpio_table, board_gpio_table, validate=True):
+ soc = openbmc_gpio_table.SocGPIOTable(soc_gpio_table)
+ gpio_configured = []
+ for gpio in board_gpio_table:
+ try:
+ soc.config_function(gpio.gpio, write_through=False)
+ gpio_configured.append(gpio.gpio)
+ except openbmc_gpio_table.ConfigUnknownFunction as e:
+ # not multiple-function GPIO pin
+ pass
+ except openbmc_gpio_table.NotSmartEnoughException as e:
+ logging.error('Failed to configure "%s" for "%s": %s'
+ % (gpio.gpio, gpio.shadow, str(e)))
+
+ soc.write_to_hw()
+
+ if validate:
+ all_functions = set(soc.get_active_functions(refresh=True))
+ for gpio in gpio_configured:
+ if gpio not in all_functions:
+ raise Exception('Failed to configure function "%s"' % gpio)
+
+ for gpio in board_gpio_table:
+ openbmc_gpio.gpio_export(gpio.gpio, gpio.shadow)
+ if gpio.value == openbmc_gpio_table.GPIO_INPUT:
+ continue
+ elif gpio.value == openbmc_gpio_table.GPIO_OUT_HIGH:
+ openbmc_gpio.gpio_set(gpio.gpio, 1)
+ elif gpio.value == openbmc_gpio_table.GPIO_OUT_LOW:
+ openbmc_gpio.gpio_set(gpio.gpio, 0)
+ else:
+ raise Exception('Invalid value "%s"' % gpio.value)
+
+def main():
+ print('Setting up GPIOs ... ', end='')
+ sys.stdout.flush()
+ openbmc_gpio.setup_shadow()
+ setup_board_gpio(soc_gpio_table, board_gpio_table)
+ print('Done')
+ sys.stdout.flush()
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py
new file mode 100644
index 0000000..dda8a98
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py
@@ -0,0 +1,269 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from soc_gpio import soc_get_register
+
+import logging
+import os
+import sys
+
+
+class NotSmartEnoughException(Exception):
+ '''There are few cases the code cannot make good decision on how to configure
+ the registers automatically. In such cases, this exception is thrown.
+ '''
+ pass
+
+
+class ConfigUnknownFunction(Exception):
+ '''Unknown function to configure exception'''
+ pass
+
+
+class BitsEqual(object):
+ def __init__(self, register, bits, value):
+ self.register = register
+ self.bits = bits
+ self.value = value
+
+ def __str__(self):
+ return '%s[%s]==0x%x' \
+ % (str(soc_get_register(self.register)), self.bits, self.value)
+
+ def get_registers(self):
+ return set([self.register])
+
+ def check(self):
+ return soc_get_register(self.register).bits_value(self.bits) \
+ == self.value
+
+ def satisfy(self, **kwargs):
+ if BitsEqual.check(self):
+ return
+ reg = soc_get_register(self.register)
+ value = self.value
+ for bit in sorted(self.bits):
+ if value & 0x1 == 0x1:
+ reg.set_bit(bit, **kwargs)
+ else:
+ reg.clear_bit(bit, **kwargs)
+ value >>= 1
+
+ def unsatisfy(self, **kwargs):
+ if not BitsEqual.check(self):
+ return
+ if len(self.bits) > 1:
+ raise NotSmartEnoughException('Not able to unsatisfy '
+ 'multi-bits equal')
+ bit = self.bits[0]
+ reg = soc_get_register(self.register)
+ value = self.value
+ if value & 0x1 == 0x1:
+ reg.clear_bit(bit, **kwargs)
+ else:
+ reg.set_bit(bit, **kwargs)
+
+
+class BitsNotEqual(BitsEqual):
+ def __str__(self):
+ return '%s[%s]!=0x%x' \
+ % (str(soc_get_register(self.register)), self.bits, self.value)
+
+ def check(self):
+ return not BitsEqual.check(self)
+
+ def satisfy(self, **kwargs):
+ BitsEqual.unsatisfy(self, **kwargs)
+
+ def unsatisfy(self, **kwargs):
+ BitsEqual.satisfy(self, **kwargs)
+
+
+class AndOrBase(object):
+ def __init__(self, left, right):
+ self.left = left
+ self.right = right
+
+ def get_registers(self):
+ return self.left.get_registers() | self.right.get_registers()
+
+ def check(self):
+ raise Exception('This method must be implemented in subclass')
+
+
+class And(AndOrBase):
+ def __str__(self):
+ return 'AND(%s, %s)' % (str(self.left), str(self.right))
+
+ def check(self):
+ return self.left.check() and self.right.check()
+
+ def satisfy(self, **kwargs):
+ if self.check():
+ return
+ self.left.satisfy(**kwargs)
+ self.right.satisfy(**kwargs)
+
+ def unsatisfy(self, **kwargs):
+ if not self.check():
+ return
+ raise NotSmartEnoughException('Not able to unsatisfy an AND condition')
+
+
+class Or(AndOrBase):
+ def __str__(self):
+ return 'OR(%s, %s)' % (str(self.left), str(self.right))
+
+ def check(self):
+ return self.left.check() or self.right.check()
+
+ def satisfy(self, **kwargs):
+ if self.check():
+ return
+ raise NotSmartEnoughException('Not able to satisfy an OR condition')
+
+ def unsatisfy(self, **kwargs):
+ if not self.check():
+ return
+ self.left.unsatisfy(**kwargs)
+ self.right.unsatisfy(**kwargs)
+
+
+class Function(object):
+ def __init__(self, name, condition=None):
+ self.name = name
+ self.condition = condition
+
+ def __str__(self):
+ return 'Function(\'%s\', %s)' % (self.name, str(self.condition))
+
+
+class SocGPIOTable(object):
+ def __init__(self, gpio_table):
+ self.soc_gpio_table = gpio_table
+ self.registers = set([]) # all HW registers used for GPIO control
+ self.functions = {}
+
+ self._parse_gpio_table()
+ self._sync_from_hw()
+
+ def _parse_gpio_table(self):
+ # first get list of registers based on the SoC GPIO table
+ for pin, funcs in self.soc_gpio_table.iteritems():
+ for func in funcs:
+ assert func.name not in self.functions
+ self.functions[func.name] = pin
+ if func.condition is not None:
+ self.registers |= func.condition.get_registers()
+
+ def _sync_from_hw(self):
+ # for each register, create an object and read the value from HW
+ for reg in self.registers:
+ soc_get_register(reg).read(refresh=True)
+
+ def write_to_hw(self):
+ for reg in self.registers:
+ soc_get_register(reg).write()
+
+ def config_function(self, func_name, write_through=True):
+ logging.debug('Configure function "%s"' % func_name)
+ if func_name not in self.functions:
+ # The function is not multi-function pin
+ raise ConfigUnknownFunction('Unknown function "%s" ' % func_name)
+ funcs = self.soc_gpio_table[self.functions[func_name]]
+ for func in funcs:
+ cond = func.condition
+ if func.name == func_name:
+ # this is the function we want to configure.
+ # if the condition is None, we are good to go,
+ # otherwiset, satisfy the condition
+ if cond is not None:
+ cond.satisfy(write_through=write_through)
+ break
+ else:
+ # this is not the funciton we want to configure.
+ # have to make this condition unsatisfied, so that we can go
+ # to the next function
+ assert cond is not None
+ cond.unsatisfy(write_through=write_through)
+
+ def _get_one_pin(self, pin, refresh):
+ if refresh:
+ self._sync_from_hw()
+ funcs = self.soc_gpio_table[pin]
+ active_func = None
+ all_funcs = []
+ for func in funcs:
+ cond = func.condition
+ all_funcs.append('%s:%s' % (func.name, str(cond)))
+ if active_func is None and (cond is None or cond.check()):
+ active_func = func.name
+
+ if active_func is None:
+ logging.error('Pin "%s" has no function set up. '
+ 'All possibile functions are %s.'
+ % (pin, ', '.join(all_funcs)))
+ return ('', '')
+ else:
+ desc = '%s => %s, functions: %s' \
+ % (pin, active_func, ', '.join(all_funcs))
+ return (active_func, desc)
+
+ def dump_pin(self, pin, out=sys.stdout, refresh=False):
+ if pin not in self.soc_gpio_table:
+ raise Exception('"%s" is not a valid pin' % pin)
+
+ _, desc = self._get_one_pin(pin, refresh)
+ out.write('%s\n' % desc)
+
+ def dump_function(self, func_name, out=sys.stdout, refresh=False):
+ if func_name not in self.functions:
+ raise Exception('"%s" is not a valid function name' % func_name)
+ pin = self.functions[func_name]
+ self.dump_pin(pin, out=out, refresh=refresh)
+
+ def dump_functions(self, out=sys.stdout, refresh=False):
+ if refresh:
+ self._sync_from_hw()
+
+ for pin in self.soc_gpio_table:
+ self.dump_pin(pin, out=out, refresh=False)
+
+ def get_active_functions(self, refresh=False):
+ if refresh:
+ self._sync_from_hw()
+
+ all = []
+ for pin in self.soc_gpio_table:
+ active, _ = self._get_one_pin(pin, False)
+ all.append(active)
+ return all
+
+
+GPIO_INPUT = 'input'
+GPIO_OUT_HIGH = 'high'
+GPIO_OUT_LOW = 'low'
+
+class BoardGPIO(object):
+ def __init__(self, gpio, shadow, value=GPIO_INPUT):
+ self.gpio = gpio
+ self.shadow = shadow
+ self.value = value
diff --git a/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_util.py b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_util.py
new file mode 100644
index 0000000..e4b40b0
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_util.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python -tt
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from soc_gpio_table import soc_gpio_table
+
+import openbmc_gpio
+import openbmc_gpio_table
+
+import argparse
+import logging
+import sys
+
+
+def _get_gpio_table():
+ gpio = openbmc_gpio_table.SocGPIOTable(soc_gpio_table)
+ return gpio
+
+
+def dump_func(args):
+ gpio = _get_gpio_table()
+ gpio.dump_functions()
+ return 0
+
+
+def config_func(args):
+ gpio = _get_gpio_table()
+ try:
+ gpio.config_function(args.function)
+ except openbmc_gpio_table.NotSmartEnoughException as e:
+ print('The code is not smart enough to set function "%s": %s\n'
+ 'Please set the function manually.'
+ % (args.function, str(e)))
+ print('The current HW setting for this function is:')
+ gpio.dump_function(args.function)
+ return -1
+ except Exception as e:
+ print('Failed to set function "%s": %s\n'
+ 'Please set the function manually.'
+ % (args.function, str(e)))
+ print('The current HW setting for this function is:')
+ gpio.dump_function(args.function)
+ logging.exception('Exception:')
+ return -2
+
+ print('Function "%s" is set' % args.function)
+ return 0
+
+
+def export_func(args):
+ openbmc_gpio.gpio_export(args.gpio, args.shadow)
+
+
+def set_func(args):
+ openbmc_gpio.gpio_set(args.gpio, args.value,
+ change_direction=False if args.keep else True)
+
+
+def get_func(args):
+ val = openbmc_gpio.gpio_get(
+ args.gpio, change_direction=False if args.keep else True)
+ print('%d' % val)
+
+
+def info_func(args):
+ res = openbmc_gpio.gpio_info(args.gpio)
+ print('GPIO info for %s:' % args.gpio)
+ print('Path: %s\nShadow: %s\nDirection: %s\nValue: %s'
+ % (res['path'], res['shadow'], res['direction'], res['value']))
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument('--debug', action='store_true',
+ help='Enable debug messages')
+
+ subparser = ap.add_subparsers()
+
+ dump_parser = subparser.add_parser(
+ 'dump', help='Dump the current HW GPIO settings')
+ dump_parser.set_defaults(func=dump_func)
+
+ config_parser = subparser.add_parser(
+ 'config', help='Configure one HW pin to a function')
+ config_parser.add_argument(
+ 'function', help='The function name to set')
+ config_parser.set_defaults(func=config_func)
+
+ export_parser = subparser.add_parser(
+ 'export', help='Export a GPIO directory')
+ export_parser.add_argument(
+ 'gpio', help='The GPIO name, i.e. "A4", or "GPIOD2"')
+ export_parser.add_argument(
+ 'shadow', default=None,
+ help='The shadow name given to this GPIO')
+ export_parser.set_defaults(func=export_func)
+
+
+ set_parser = subparser.add_parser(
+ 'set', help='Set a value for a GPIO')
+ set_parser.add_argument(
+ 'gpio', help='The GPIO name or number')
+ set_parser.add_argument(
+ 'value', type=int, choices=[0, 1],
+ help='The value to set')
+ set_parser.add_argument(
+ '-k', '--keep', action='store_true',
+ help='Keep the GPIO direction')
+ set_parser.set_defaults(func=set_func)
+
+ get_parser = subparser.add_parser(
+ 'get', help='Get a GPIO\'s value')
+ get_parser.add_argument(
+ 'gpio', help='The GPIO name or number')
+ get_parser.add_argument(
+ '-k', '--keep', action='store_true',
+ help='Keep the GPIO direction')
+ get_parser.set_defaults(func=get_func)
+
+ info_parser = subparser.add_parser(
+ 'info', help='Get a GPIO\'s info')
+ info_parser.add_argument(
+ 'gpio', help='The GPIO name or number')
+ info_parser.set_defaults(func=info_func)
+
+ args = ap.parse_args()
+
+ logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO,
+ format='%(asctime)s: %(message)s')
+
+ return args.func(args)
+
+
+rc = main()
+sys.exit(rc)
diff --git a/common/recipes-utils/openbmc-gpio/files/phymemory.py b/common/recipes-utils/openbmc-gpio/files/phymemory.py
new file mode 100644
index 0000000..97a0d6e
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/phymemory.py
@@ -0,0 +1,100 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import subprocess
+import logging
+
+
+class PhyMemory(object):
+ def __init__(self, addr, name=''):
+ self.addr = addr
+ self.name = name
+ self.write_pending = False
+ self.value = 0
+
+ def __del__(self):
+ if self.write_pending:
+ logging.warning('Value (0x%x) is not wrote back to address (0x%x)'
+ % (self.value, self.addr))
+
+ def __str__(self):
+ if self.name == '':
+ return '0x%x' % self.addr
+ else:
+ return self.name
+
+ def _read_hw(self):
+ if self.write_pending:
+ raise Exception('Value (0x%x) is not wrote back to address (0x%x) '
+ 'before reading HW' % (self.value, self.addr))
+ cmd = ['devmem', '0x%x' % self.addr]
+ out = subprocess.check_output(cmd)
+ self.value = int(out, 16)
+ logging.debug('Read from %s @0x%x, got value (0x%x)'
+ % (str(self), self.addr, self.value))
+
+ def read(self, refresh=True):
+ if refresh:
+ self._read_hw()
+ return self.value
+
+ def write(self, force=False):
+ if not force and not self.write_pending:
+ return
+ cmd = ['devmem', '0x%x' % self.addr, '32', '0x%x' % self.value]
+ subprocess.check_call(cmd)
+ self.write_pending = False
+ logging.debug('Wrote to %s address @0x%x with value (0x%x)'
+ % (str(self), self.addr, self.value))
+
+ def set_bit(self, bit, write_through=True):
+ assert 0 <= bit <= 31
+ self.value |= 1 << bit
+ self.write_pending = True
+ logging.debug('Set bit %s[%d] (0x%x)' % (str(self), bit, self.value))
+ if write_through:
+ self.write()
+
+ def clear_bit(self, bit, write_through=True):
+ assert 0 <= bit <= 31
+ self.value &= ~(1 << bit)
+ self.write_pending = True
+ logging.debug('Clear bit %s[%d] (0x%x)' % (str(self), bit, self.value))
+ if write_through:
+ self.write()
+
+ def is_bit_set(self, bit, refresh=False):
+ assert 0 <= bit <= 31
+ self.read(refresh=refresh)
+ rc = True if self.value & (0x1 << bit) else False
+ logging.debug('Test bit %s[%d](0x%x): %s'
+ % (str(self), bit, self.value, rc))
+ return rc
+
+ def bits_value(self, bits, refresh=False):
+ self.read(refresh=refresh)
+ value = 0
+ for bit in sorted(bits, reverse=True):
+ assert 0 <= bit <= 31
+ value = (value << 1) | ((self.value >> bit) & 0x1)
+ logging.debug('%s%s is 0x%x (0x%x)'
+ % (str(self), bits, value, self.value))
+ return value
diff --git a/common/recipes-utils/openbmc-gpio/files/setup.py b/common/recipes-utils/openbmc-gpio/files/setup.py
new file mode 100644
index 0000000..59c7de4
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/setup.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+
+from distutils.core import setup
+
+setup(
+ name = 'openbmc-gpio',
+ version = '1.0',
+ description = 'OpenBMC GPIO utilities',
+ author = 'Tian Fang',
+ author_email = 'tfang@fb.com',
+ license = 'GPLv2',
+ py_modules=['openbmc_gpio',
+ 'openbmc_gpio_table',
+ 'phymemory',
+ 'soc_gpio',
+ 'soc_gpio_table',
+ 'board_gpio_table',
+ ],
+)
diff --git a/common/recipes-utils/openbmc-gpio/files/soc_gpio.py b/common/recipes-utils/openbmc-gpio/files/soc_gpio.py
new file mode 100644
index 0000000..2718af8
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/soc_gpio.py
@@ -0,0 +1,19 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+def soc_get_register(addr):
+ raise Exception('Virtual function. Not implemented')
diff --git a/common/recipes-utils/openbmc-gpio/files/soc_gpio_table.py b/common/recipes-utils/openbmc-gpio/files/soc_gpio_table.py
new file mode 100644
index 0000000..45713e9
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/soc_gpio_table.py
@@ -0,0 +1,23 @@
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+# This is an dummy SoC GPIO table. If this is included in the final image,
+# please double check the configuration of your image to define the correct
+# SoC GPIO table to be used for your board.
+
+soc_gpio_table = {
+}
diff --git a/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb b/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb
new file mode 100644
index 0000000..6bf4cc1
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb
@@ -0,0 +1,75 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "OpenBMC GPIO utilies"
+SECTION = "base"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
+
+SRC_URI = " \
+ file://COPYING \
+ file://board_gpio_table.py \
+ file://openbmc_gpio.py \
+ file://openbmc_gpio_table.py \
+ file://openbmc_gpio_setup.py \
+ file://openbmc_gpio_util.py \
+ file://phymemory.py \
+ file://setup.py \
+ file://soc_gpio.py \
+ file://soc_gpio_table.py \
+ "
+
+S = "${WORKDIR}"
+
+OPENBMC_GPIO_UTILS = " \
+ openbmc_gpio_util.py \
+ "
+
+OPENBMC_GPIO_SOC_TABLE = "soc_gpio_table.py"
+
+# Change OPENBMC_GPIO_SETUP to "0" to exclude openbmc_gpio_setup.py from the image
+OPENBMC_GPIO_SETUP = "1"
+
+inherit distutils
+
+DEPENDS_${PN} = "python python-distribute update-rc.d-native"
+
+RDEPENDS_${PN} = "python-core python-argparse python-subprocess"
+
+do_board_defined_soc_table() {
+ if [ "${OPENBMC_GPIO_SOC_TABLE}" != "soc_gpio_table.py" ]; then
+ mv -f "${S}/${OPENBMC_GPIO_SOC_TABLE}" "${S}/soc_gpio_table.py"
+ fi
+}
+addtask board_defined_soc_table after do_unpack before do_build
+
+do_install_append() {
+ localbindir="${D}/usr/local/bin"
+ install -d ${localbindir}
+ for f in ${OPENBMC_GPIO_UTILS}; do
+ install -m 755 $f ${localbindir}/${f}
+ done
+
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/rcS.d
+ if [ "${OPENBMC_GPIO_SETUP}" == "1" ]; then
+ install -m 755 openbmc_gpio_setup.py ${D}${sysconfdir}/init.d/openbmc_gpio_setup.py
+ update-rc.d -r ${D} openbmc_gpio_setup.py start 59 S .
+ fi
+}
+
+FILES_${PN} += "/usr/local/bin ${sysconfdir}"
diff --git a/common/recipes-utils/openbmc-utils/files/COPYING b/common/recipes-utils/openbmc-utils/files/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/common/recipes-utils/openbmc-utils/files/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/common/recipes-utils/openbmc-utils/files/openbmc-utils.sh b/common/recipes-utils/openbmc-utils/files/openbmc-utils.sh
new file mode 100644
index 0000000..885a6eb
--- /dev/null
+++ b/common/recipes-utils/openbmc-utils/files/openbmc-utils.sh
@@ -0,0 +1,133 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+DEVMEM=/sbin/devmem
+SHADOW_GPIO=/tmp/gpionames
+
+devmem_set_bit() {
+ local addr
+ local val
+ addr=$1
+ val=$($DEVMEM $addr)
+ val=$((val | (0x1 << $2)))
+ $DEVMEM $addr 32 $val
+}
+
+devmem_clear_bit() {
+ local addr
+ local val
+ addr=$1
+ val=$($DEVMEM $addr)
+ val=$((val & ~(0x1 << $2)))
+ $DEVMEM $addr 32 $val
+}
+
+GPIODIR="/sys/class/gpio"
+GPIOEXPORT="$GPIODIR/export"
+
+gpio_dir() {
+ echo "$GPIODIR/gpio$1"
+}
+
+gpio_name2value() {
+ local first remaining base val
+ remaining=$1
+ base="${SHADOW_GPIO}/${remaining}"
+ if [ -L "${base}" ]; then
+ val=$(readlink -f ${base} 2>/dev/null)
+ if [ -n "${val}" ]; then
+ val=${val##*gpio}
+ if [ -n "${val}" ]; then
+ echo "$val"
+ return
+ fi
+ fi
+ fi
+ val=0
+ while [ -n "$remaining" ]; do
+ first=${remaining:0:1}
+ case "$first" in
+ [[:lower:]])
+ base=$(printf "%d" "'$first'")
+ base=$((base - 96))
+ val=$((val * 26 + base))
+ ;;
+ [[:upper:]])
+ base=$(printf "%d" "'$first'")
+ base=$((base - 64))
+ val=$((val * 26 + base))
+ ;;
+ *)
+ if [ $val -gt 0 ]; then
+ val=$((val-1))
+ fi
+ val=$((val * 8 + $remaining))
+ break
+ ;;
+ esac
+ remaining=${remaining:1}
+ done
+ echo "$val"
+}
+
+gpio_export() {
+ local gpio
+ gpio=$(gpio_name2value $1)
+ dir=$(gpio_dir $gpio)
+ if [ ! -d ${dir} ]; then
+ echo $gpio > $GPIOEXPORT
+ fi
+ if [ $# -gt 1 ]; then
+ if [ ! -d $SHADOW_GPIO ]; then
+ mkdir -p $SHADOW_GPIO
+ fi
+ ln -s $dir $SHADOW_GPIO/$2
+ fi
+}
+
+gpio_set() {
+ local gpio
+ local val
+ gpio=$(gpio_name2value $1)
+ val=$2
+ dir=$(gpio_dir $gpio)
+ if [ ! -d ${dir} ]; then
+ echo $gpio > $GPIOEXPORT
+ fi
+ echo $val > ${dir}/value
+ echo out > ${dir}/direction
+}
+
+gpio_get() {
+ local gpio
+ local val
+ gpio=$(gpio_name2value $1)
+ dir=$(gpio_dir $gpio)
+ if [ ! -d ${dir} ]; then
+ echo $gpio > $GPIOEXPORT
+ fi
+ echo in > ${dir}/direction
+ cat ${dir}/value
+}
+
+if [ -f "/usr/local/bin/soc-utils.sh" ]; then
+ source "/usr/local/bin/soc-utils.sh"
+fi
+
+if [ -f "/usr/local/bin/board-utils.sh" ]; then
+ source "/usr/local/bin/board-utils.sh"
+fi
diff --git a/common/recipes-utils/openbmc-utils/openbmc-utils_0.1.bb b/common/recipes-utils/openbmc-utils/openbmc-utils_0.1.bb
new file mode 100644
index 0000000..f40d48b
--- /dev/null
+++ b/common/recipes-utils/openbmc-utils/openbmc-utils_0.1.bb
@@ -0,0 +1,48 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+SUMMARY = "OpenBMC Utilities"
+DESCRIPTION = "Various OpenBMC utilities"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
+
+SRC_URI = " \
+ file://COPYING \
+ file://openbmc-utils.sh \
+ "
+
+OPENBMC_UTILS_FILES = " \
+ openbmc-utils.sh \
+ "
+
+S = "${WORKDIR}"
+
+do_install() {
+ pkgdir="/usr/local/packages/utils"
+ dstdir="${D}${pkgdir}"
+ install -d $dstdir
+ localbindir="${D}/usr/local/bin"
+ install -d ${localbindir}
+ for f in ${OPENBMC_UTILS_FILES}; do
+ install -m 755 $f ${dstdir}/${f}
+ ln -s ${pkgdir}/${f} ${localbindir}
+ done
+}
+
+FILES_${PN} += "/usr/local"
diff --git a/common/recipes-utils/spatula/files/setup-spatula.sh b/common/recipes-utils/spatula/files/setup-spatula.sh
new file mode 100644
index 0000000..391a212
--- /dev/null
+++ b/common/recipes-utils/spatula/files/setup-spatula.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+### BEGIN INIT INFO
+# Provides: setup-spatula-wrapper
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Set Spatula Wrapper
+### END INIT INFO
+
+# source function library
+. /etc/init.d/functions
+
+ACTION="$1"
+CMD="/usr/local/bin/spatula_wrapper.py"
+case "$ACTION" in
+ start)
+ echo -n "Setting up Spatula: "
+ pid=$(ps | grep -v grep | grep $CMD | awk '{print $1}')
+ if [ $pid ]; then
+ echo "already running"
+ else
+ $CMD > /var/log/spatula.log 2>&1 &
+ echo "done."
+ fi
+ ;;
+ stop)
+ echo -n "Stopping Spatula: "
+ pid=$(ps | grep -v grep | grep $CMD | awk '{print $1}')
+ if [ $pid ]; then
+ kill $pid
+ fi
+ echo "done."
+ ;;
+ restart)
+ echo -n "Restarting Spatula: "
+ pid=$(ps | grep -v grep | grep $CMD | awk '{print $1}')
+ if [ $pid ]; then
+ kill $pid
+ fi
+ sleep 1
+ $CMD > /var/log/spatula.log 2>&1 &
+ echo "done."
+ ;;
+ status)
+ if [[ -n $(ps | grep -v grep | grep $CMD | awk '{print $1}') ]]; then
+ echo "Spatula is running"
+ else
+ echo "Spatula is stopped"
+ fi
+ ;;
+ *)
+ N=${0##*/}
+ N=${N#[SK]??}
+ echo "Usage: $N {start|stop|status|restart}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/common/recipes-utils/spatula/files/spatula_wrapper.py b/common/recipes-utils/spatula/files/spatula_wrapper.py
new file mode 100644
index 0000000..2717bef
--- /dev/null
+++ b/common/recipes-utils/spatula/files/spatula_wrapper.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+import urllib2, urllib
+import logging
+import os
+import subprocess
+import time
+import argparse
+
+SPATULA_FILE = '/etc/spatula/spatula'
+LOG_FORMAT = '[%(levelname)s] %(asctime)s: %(message)s'
+DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
+DEFAULT_SLEEP = 900 # default sleep 15 mins
+
+class SpatulaWrapper(object):
+ def __init__(self, address='fe80::2', interface='usb0',
+ port=8087, ssl=False):
+ proto = 'http'
+ if ssl:
+ proto = 'https'
+ self.url = '{proto}://{address}%{iface}:{port}'.format(
+ proto = proto,
+ address = address,
+ iface = interface,
+ port = port)
+
+ def _getSpatula(self, endpoint='/spatula'):
+ '''
+ Get the executable spatula script from the host.
+ '''
+ url = '{}{}'.format(self.url, endpoint)
+ try:
+ request = urllib2.Request(url)
+ response = urllib2.urlopen(request)
+ return response.read()
+ except Exception as err:
+ raise Exception('failed getting Spatula {}: {}'.format(url, err))
+
+ def _success(self, endpoint='/success'):
+ '''
+ Api to report the timestamp of a successful run
+ '''
+ query = urllib.urlencode({'timestamp': time.time()})
+ url = '{}{}?{}'.format(self.url, endpoint, query)
+ try:
+ request = urllib2.Request(url)
+ response = urllib2.urlopen(request)
+ return response.read()
+ except Exception as err:
+ raise Exception('failed report success {}: {}'.format(url, err))
+
+ def _error(self, error, endpoint='/error'):
+ '''
+ Api to report the timestamp and the error when spatula fails
+ '''
+ query = urllib.urlencode({'timestamp': time.time(), 'error': error})
+ url = '{}{}?{}'.format(self.url, endpoint, query)
+ try:
+ request = urllib2.Request(url)
+ response = urllib2.urlopen(request)
+ return response.read()
+ except Exception as err:
+ raise Exception('failed report error [{}]: {}'.format(url, err))
+
+ def _execute(self):
+ try:
+ # get the executable from host
+ if not os.path.exists(os.path.dirname(SPATULA_FILE)):
+ os.makedirs(os.path.dirname(SPATULA_FILE))
+ with open(SPATULA_FILE, 'w+') as file:
+ file.write(self._getSpatula())
+ file.close()
+ # set the permission
+ os.chmod(SPATULA_FILE, 0755)
+ # run the executable file
+ spatula = subprocess.Popen([SPATULA_FILE],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = spatula.communicate()
+ if spatula.returncode != 0:
+ raise Exception('spatula failed: {}'.format(err))
+ self._success()
+ except Exception as err:
+ self._error(err)
+ raise err
+
+ def run(self, sleep):
+ while True:
+ try:
+ self._execute()
+ except Exception as err:
+ logging.error(err)
+ time.sleep(sleep)
+
+if __name__ == '__main__':
+ args = argparse.ArgumentParser()
+ args.add_argument('-s', '--sleep', default=DEFAULT_SLEEP,
+ help='Sleep time between spatula runs (default=%(default)s)')
+ params = args.parse_args()
+ logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT)
+ wrapper = SpatulaWrapper()
+ wrapper.run(params.sleep)
diff --git a/common/recipes-utils/spatula/spatula_0.1.bb b/common/recipes-utils/spatula/spatula_0.1.bb
new file mode 100644
index 0000000..dd54ccd
--- /dev/null
+++ b/common/recipes-utils/spatula/spatula_0.1.bb
@@ -0,0 +1,47 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+SUMMARY = "Configure the BMC"
+DESCRIPTION = "The script communicates with host and configures BMC."
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://spatula_wrapper.py;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0"
+
+
+DEPENDS_append = " update-rc.d-native"
+
+SRC_URI = "file://setup-spatula.sh \
+ file://spatula_wrapper.py \
+ "
+
+S = "${WORKDIR}"
+
+binfiles = "spatula_wrapper.py"
+
+do_install() {
+ bin="${D}/usr/local/bin"
+ install -d $bin
+ for f in ${binfiles}; do
+ install -m 755 $f ${bin}/$f
+ done
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/rcS.d
+ install -m 755 setup-spatula.sh ${D}${sysconfdir}/init.d/setup-spatula.sh
+ update-rc.d -r ${D} setup-spatula.sh start 95 2 3 4 5 .
+}
+
+FILES_${PN} = "${prefix}/local/bin ${sysconfdir} "
OpenPOWER on IntegriCloud