Add wistron oem command to detect riser-f

PNOR needs to know whether riser-f is present when poweron, so we add
an oem command to detect whether riser-f is present.
The result will return two bytes of data, the first byte is bus9 and
the second byte is bus10.

Return data will have 0x00 or 0x01.
0x00 means riser-f not present
0x01 means riser-f present

Change-Id: I7d932b8e69b820b67466b83998d5bd3b8c472720
Signed-off-by: Ben Pai <Ben_Pai@wistron.com>
diff --git a/smbus.cpp b/smbus.cpp
new file mode 100644
index 0000000..80f7cac
--- /dev/null
+++ b/smbus.cpp
@@ -0,0 +1,177 @@
+#include "smbus.hpp"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <mutex>
+
+#include "i2c.h"
+
+#define MAX_I2C_BUS 30
+
+static int fd[MAX_I2C_BUS] = {0};
+
+namespace phosphor
+{
+namespace smbus
+{
+
+std::mutex gMutex;
+
+int phosphor::smbus::Smbus::open_i2c_dev(int i2cbus, char* filename,
+                                         size_t size, int quiet)
+{
+    int file;
+
+    snprintf(filename, size, "/dev/i2c/%d", i2cbus);
+    filename[size - 1] = '\0';
+    file = open(filename, O_RDWR);
+
+    if (file < 0 && (errno == ENOENT || errno == ENOTDIR))
+    {
+        sprintf(filename, "/dev/i2c-%d", i2cbus);
+        file = open(filename, O_RDWR);
+    }
+
+    if (file < 0 && !quiet)
+    {
+        if (errno == ENOENT)
+        {
+            fprintf(stderr,
+                    "Error: Could not open file "
+                    "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
+                    i2cbus, i2cbus, strerror(ENOENT));
+        }
+        else
+        {
+            fprintf(stderr,
+                    "Error: Could not open file "
+                    "`%s': %s\n",
+                    filename, strerror(errno));
+            if (errno == EACCES)
+                fprintf(stderr, "Run as root?\n");
+        }
+    }
+
+    return file;
+}
+
+int phosphor::smbus::Smbus::smbusInit(int smbus_num)
+{
+    int res = 0;
+    char filename[20];
+
+    gMutex.lock();
+
+    fd[smbus_num] = open_i2c_dev(smbus_num, filename, sizeof(filename), 0);
+    if (fd[smbus_num] < 0)
+    {
+        gMutex.unlock();
+
+        return -1;
+    }
+
+    res = fd[smbus_num];
+
+    gMutex.unlock();
+
+    return res;
+}
+
+void phosphor::smbus::Smbus::smbusClose(int smbus_num)
+{
+    close(fd[smbus_num]);
+}
+
+int phosphor::smbus::Smbus::set_slave_addr(int file, int address, int force)
+{
+    /* With force, let the user read from/write to the registers
+       even when a driver is also running */
+    if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0)
+    {
+        fprintf(stderr, "Error: Could not set address to 0x%02x: %s\n", address,
+                strerror(errno));
+        return -errno;
+    }
+
+    return 0;
+}
+
+int phosphor::smbus::Smbus::SetSmbusCmdByte(int smbus_num, int8_t device_addr,
+                                            int8_t smbuscmd, int8_t data)
+{
+    int res;
+
+    gMutex.lock();
+    if (fd[smbus_num] > 0)
+    {
+        res = set_slave_addr(fd[smbus_num], device_addr, I2C_SLAVE_FORCE);
+        if (res < 0)
+        {
+            fprintf(stderr,
+                    "set PMBUS BUS%d to slave address 0x%02X failed (%s)\n",
+                    smbus_num, device_addr, strerror(errno));
+            close(fd[smbus_num]);
+
+            gMutex.unlock();
+            return -1;
+        }
+    }
+
+    res = i2c_smbus_write_byte_data(fd[smbus_num], smbuscmd, data);
+    if (res < 0)
+    {
+        fprintf(stderr, "Error: Read failed\n");
+        gMutex.unlock();
+
+        return -1;
+    }
+
+    gMutex.unlock();
+    return res;
+}
+
+int phosphor::smbus::Smbus::GetSmbusCmdByte(int smbus_num, int8_t device_addr,
+                                            int8_t smbuscmd)
+{
+    int res;
+
+    gMutex.lock();
+    if (fd[smbus_num] > 0)
+    {
+        res = set_slave_addr(fd[smbus_num], device_addr, I2C_SLAVE_FORCE);
+
+        if (res < 0)
+        {
+            fprintf(stderr,
+                    "set PMBUS BUS%d to slave address 0x%02X failed (%s)\n",
+                    smbus_num, device_addr, strerror(errno));
+            close(fd[smbus_num]);
+
+            gMutex.unlock();
+            return -1;
+        }
+    }
+
+    res = i2c_smbus_read_byte_data(fd[smbus_num], smbuscmd);
+    if (res < 0)
+    {
+        fprintf(stderr, "Error: Read failed\n");
+        gMutex.unlock();
+
+        return -1;
+    }
+
+    gMutex.unlock();
+    return res;
+}
+
+} // namespace smbus
+} // namespace phosphor