aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrand SIMONNET <bsimonnet@google.com>2016-04-26 16:50:43 -0700
committerBertrand SIMONNET <bsimonnet@google.com>2016-05-24 14:38:26 -0700
commitf70f9c76555ed6186173e5cb93d4c79f6c3e1e4f (patch)
treebed069998906d40da5d2a20eb59e9b77d11d2379
parentefb7c86c45b774dc0b142b089d8bd2229ae57a33 (diff)
downloadperipheralmanager-f70f9c76555ed6186173e5cb93d4c79f6c3e1e4f.tar.gz
Implement the backend for UART support.
This includes: * the hal hooks to register UART devices. * the UART sysfs driver. * the UART manager. Bug: 27898961 Change-Id: I48488b2684c9198c70a908cef3ef6c2032eb4bfe
-rw-r--r--daemon/Android.mk2
-rw-r--r--daemon/peripheral_manager.cc22
-rw-r--r--daemon/uart_driver.h74
-rw-r--r--daemon/uart_driver_sysfs.cc204
-rw-r--r--daemon/uart_driver_sysfs.h59
-rw-r--r--daemon/uart_manager.cc119
-rw-r--r--daemon/uart_manager.h93
-rw-r--r--hal/hardware/peripheral_io.h24
8 files changed, 597 insertions, 0 deletions
diff --git a/daemon/Android.mk b/daemon/Android.mk
index 6e8c6ed..935ee62 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -43,6 +43,8 @@ libperipheralman_internal_CommonSources := \
pin_mux_manager.cc \
spi_driver_spidev.cc \
spi_manager.cc \
+ uart_driver_sysfs.cc \
+ uart_manager.cc \
# peripheralman executable
# ========================================================
diff --git a/daemon/peripheral_manager.cc b/daemon/peripheral_manager.cc
index c946932..ba8c6aa 100644
--- a/daemon/peripheral_manager.cc
+++ b/daemon/peripheral_manager.cc
@@ -30,6 +30,8 @@
#include "led_manager.h"
#include "pin_mux_manager.h"
#include "spi_driver_spidev.h"
+#include "uart_driver_sysfs.h"
+#include "uart_manager.h"
namespace android {
namespace {
@@ -57,6 +59,15 @@ static int RegisterLedSysfs(const char* name, const char* sysfs_name) {
return LedManager::GetLedManager()->RegisterLedSysfs(name, sysfs_name);
}
+// Uart callbacks
+static int RegisterUartBus(const char* name, const char* dev_name) {
+ return UartManager::GetManager()->RegisterUartDevice(name, dev_name);
+}
+
+static int SetUartPinMux(const char* name, const char* source) {
+ return UartManager::GetManager()->SetPinMux(name, source);
+}
+
// I2c callbacks
static int RegisterI2cDevBus(const char* name, uint32_t bus) {
return I2cManager::GetI2cManager()->RegisterI2cDevBus(name, bus);
@@ -158,6 +169,13 @@ bool PeripheralManager::RegisterDrivers() {
LOG(ERROR) << "Failed to load driver: LedDriverSysfs";
return false;
}
+ if (!UartManager::GetManager()->RegisterDriver(
+ std::unique_ptr<UartDriverInfoBase>(
+ new UartDriverInfo<UartDriverSysfs, CharDeviceFactory*>(
+ nullptr)))) {
+ LOG(ERROR) << "Failed to load driver: UartDriverSysfs";
+ return false;
+ }
return true;
}
@@ -183,6 +201,10 @@ bool PeripheralManager::InitHal() {
// Led
.register_led_sysfs = RegisterLedSysfs,
+ // Uart
+ .register_uart_bus = RegisterUartBus,
+ .set_uart_pin_mux = SetUartPinMux,
+
// I2c
.register_i2c_dev_bus = RegisterI2cDevBus,
.set_i2c_pin_mux = SetI2cPinMux,
diff --git a/daemon/uart_driver.h b/daemon/uart_driver.h
new file mode 100644
index 0000000..7e951a8
--- /dev/null
+++ b/daemon/uart_driver.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_H_
+#define SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <base/macros.h>
+
+namespace android {
+
+class UartDriverInterface {
+ public:
+ virtual ~UartDriverInterface() {}
+
+ // TODO(leecam): Init should have generic params.
+ virtual bool Init(const std::string& name) = 0;
+
+ virtual int SetBaudrate(uint32_t baudrate) = 0;
+
+ virtual int Write(const std::vector<uint8_t>& data,
+ uint32_t* bytes_written) = 0;
+
+ virtual int Read(std::vector<uint8_t>* data,
+ uint32_t size,
+ uint32_t* bytes_read) = 0;
+};
+
+class UartDriverInfoBase {
+ public:
+ virtual ~UartDriverInfoBase() {}
+
+ virtual std::string Compat() = 0;
+ virtual std::unique_ptr<UartDriverInterface> Probe() = 0;
+};
+
+template <class T, class PARAM>
+class UartDriverInfo : public UartDriverInfoBase {
+ public:
+ UartDriverInfo(PARAM param) : param_(param) {}
+ ~UartDriverInfo() override {}
+
+ std::string Compat() override { return T::Compat(); }
+
+ std::unique_ptr<UartDriverInterface> Probe() override {
+ return std::unique_ptr<UartDriverInterface>(new T(param_));
+ }
+
+ private:
+ PARAM param_;
+};
+
+} // namespace android
+
+#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_H_
diff --git a/daemon/uart_driver_sysfs.cc b/daemon/uart_driver_sysfs.cc
new file mode 100644
index 0000000..41e3064
--- /dev/null
+++ b/daemon/uart_driver_sysfs.cc
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "uart_driver_sysfs.h"
+
+#include <fcntl.h>
+#include <termios.h>
+
+#include <base/logging.h>
+
+#include "char_device.h"
+
+namespace android {
+
+UartDriverSysfs::UartDriverSysfs(CharDeviceFactory* factory)
+ : char_device_factory_(factory) {}
+
+UartDriverSysfs::~UartDriverSysfs() {}
+
+bool UartDriverSysfs::Init(const std::string& name) {
+ path_ = name;
+
+ // Get a char device. If char_device_factory_ is set
+ // then this is a unittest and the char device is provided
+ // by the test. Otherwise create a normal CharDevice.
+ if (!char_device_factory_) {
+ char_interface_.reset(new CharDevice());
+ } else {
+ char_interface_ = char_device_factory_->NewCharDevice();
+ }
+
+ // Open as non-blocking as we don't want peripheral_manager to block on a
+ // single client read.
+ int fd = char_interface_->Open(path_.c_str(), O_RDWR | O_NONBLOCK);
+ if (fd < 0) {
+ PLOG(WARNING) << "Failed to open " << path_;
+ return false;
+ }
+
+ // Configure the device in raw mode.
+ struct termios config;
+ if (char_interface_->Ioctl(fd, TCGETS, &config)) {
+ PLOG(ERROR) << "Failed to read the tty config";
+ close(fd);
+ return false;
+ }
+ cfmakeraw(&config);
+
+ if (char_interface_->Ioctl(fd, TCSETSF, &config)) {
+ PLOG(ERROR) << "Failed to configure the UART device as Raw.";
+ close(fd);
+ return false;
+ }
+
+ fd_ = fd;
+ return true;
+}
+
+int UartDriverSysfs::SetBaudrate(uint32_t baudrate) {
+ speed_t s;
+ switch (baudrate) {
+ case 0:
+ s = B0;
+ break;
+
+ case 50:
+ s = B50;
+ break;
+
+ case 75:
+ s = B75;
+ break;
+
+ case 110:
+ s = B110;
+ break;
+
+ case 134:
+ s = B134;
+ break;
+
+ case 150:
+ s = B150;
+ break;
+
+ case 200:
+ s = B200;
+ break;
+
+ case 300:
+ s = B300;
+ break;
+
+ case 600:
+ s = B600;
+ break;
+
+ case 1200:
+ s = B1200;
+ break;
+
+ case 1800:
+ s = B1800;
+ break;
+
+ case 2400:
+ s = B2400;
+ break;
+
+ case 4800:
+ s = B4800;
+ break;
+
+ case 9600:
+ s = B9600;
+ break;
+
+ case 19200:
+ s = B19200;
+ break;
+
+ case 38400:
+ s = B38400;
+ break;
+
+ case 57600:
+ s = B57600;
+ break;
+
+ case 115200:
+ s = B115200;
+ break;
+
+ case 230400:
+ s = B230400;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ struct termios config;
+
+ if (char_interface_->Ioctl(fd_, TCGETS, &config) != 0 ||
+ cfsetspeed(&config, s) != 0 ||
+ char_interface_->Ioctl(fd_, TCSETS, &config) != 0) {
+ LOG(ERROR) << "Failed to set the UART baurate to " << baudrate;
+ return EIO;
+ }
+
+ return 0;
+}
+
+int UartDriverSysfs::Write(const std::vector<uint8_t>& data,
+ uint32_t* bytes_written) {
+ errno = 0;
+ int ret = char_interface_->Write(fd_, data.data(), data.size());
+
+ if (ret == -1) {
+ PLOG(ERROR) << "Failed to write to UART device";
+ *bytes_written = 0;
+ return EIO;
+ }
+
+ *bytes_written = ret;
+ return 0;
+}
+
+int UartDriverSysfs::Read(std::vector<uint8_t>* data,
+ uint32_t size,
+ uint32_t* bytes_read) {
+ errno = 0;
+ data->resize(size);
+
+ int ret = char_interface_->Read(fd_, data->data(), size);
+
+ if (ret == -1) {
+ *bytes_read = 0;
+ data->resize(0);
+ if (errno == EAGAIN) {
+ return EAGAIN;
+ }
+ PLOG(ERROR) << "Failed to read from UART device";
+ return EIO;
+ }
+
+ *bytes_read = ret;
+ data->resize(ret);
+ return 0;
+}
+
+} // namespace android
diff --git a/daemon/uart_driver_sysfs.h b/daemon/uart_driver_sysfs.h
new file mode 100644
index 0000000..d8f6e16
--- /dev/null
+++ b/daemon/uart_driver_sysfs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_SYSFS_H_
+#define SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_SYSFS_H_
+
+#include <stdint.h>
+
+#include <android-base/unique_fd.h>
+#include <base/macros.h>
+
+#include "char_device.h"
+#include "uart_driver.h"
+
+namespace android {
+
+class UartDriverSysfs : public UartDriverInterface {
+ public:
+ UartDriverSysfs(CharDeviceFactory* factory);
+ ~UartDriverSysfs();
+
+ static std::string Compat() { return "UARTSYSFS"; }
+
+ bool Init(const std::string& name) override;
+
+ int SetBaudrate(uint32_t baudrate) override;
+
+ int Write(const std::vector<uint8_t>& data, uint32_t* bytes_written) override;
+
+ int Read(std::vector<uint8_t>* data,
+ uint32_t size,
+ uint32_t* bytes_read) override;
+
+ private:
+ int fd_;
+ std::string path_;
+
+ CharDeviceFactory* char_device_factory_;
+ std::unique_ptr<CharDeviceInterface> char_interface_;
+
+ DISALLOW_COPY_AND_ASSIGN(UartDriverSysfs);
+};
+
+} // namespace android
+
+#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_UART_DRIVER_SYSFS_H_
diff --git a/daemon/uart_manager.cc b/daemon/uart_manager.cc
new file mode 100644
index 0000000..bc98111
--- /dev/null
+++ b/daemon/uart_manager.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "uart_manager.h"
+
+#include "uart_driver_sysfs.h"
+
+#include <base/logging.h>
+
+namespace android {
+
+std::unique_ptr<UartManager> g_uart_manager;
+
+UartManager* UartManager::GetManager() {
+ if (!g_uart_manager) {
+ g_uart_manager.reset(new UartManager);
+ }
+ return g_uart_manager.get();
+}
+
+void UartManager::ResetManager() {
+ g_uart_manager.reset();
+}
+
+UartManager::UartManager() {}
+
+UartManager::~UartManager() {}
+
+bool UartManager::RegisterDriver(
+ std::unique_ptr<UartDriverInfoBase> driver_info) {
+ std::string key = driver_info->Compat();
+ driver_infos_[key] = std::move(driver_info);
+ return true;
+}
+
+bool UartManager::RegisterUartDevice(const std::string& name,
+ const std::string& uart_device_name) {
+ if (uart_devices_.count(name)) {
+ LOG(ERROR) << "Uart device " << name << " is already registered";
+ return false;
+ }
+ uart_devices_[name].name = name;
+ uart_devices_[name].path = uart_device_name;
+ return true;
+}
+
+bool UartManager::SetPinMux(const std::string& name,
+ const std::string& pin_mux) {
+ auto bus_it = uart_devices_.find(name);
+ if (bus_it == uart_devices_.end()) {
+ LOG(ERROR) << "Uart device " << name << " is not registered";
+ return false;
+ }
+
+ bus_it->second.mux = pin_mux;
+ return true;
+}
+
+std::vector<std::string> UartManager::GetDevicesList() {
+ std::vector<std::string> list;
+ for (const auto& it : uart_devices_) {
+ list.push_back(it.first);
+ }
+ return list;
+}
+
+bool UartManager::HasUartDevice(const std::string& name) {
+ return uart_devices_.count(name);
+}
+
+std::unique_ptr<UartDevice> UartManager::OpenUartDevice(
+ const std::string& name) {
+ // Get the Bus from the BSP.
+ auto bus_it = uart_devices_.find(name);
+ if (bus_it == uart_devices_.end())
+ return nullptr;
+
+ // Check its not already in use
+ if (bus_it->second.driver_)
+ return nullptr;
+
+ // Find a driver.
+ // Currently there is only hardcoded support for UARTSYSFS
+ auto driver_info_it = driver_infos_.find(UartDriverSysfs::Compat());
+
+ // Fail if there is no driver.
+ if (driver_info_it == driver_infos_.end())
+ return nullptr;
+
+ std::unique_ptr<UartDriverInterface> driver(driver_info_it->second->Probe());
+
+ if (!driver->Init(bus_it->second.path))
+ return nullptr;
+
+ // Set Pin muxing.
+ if (!bus_it->second.mux.empty()) {
+ PinMuxManager::GetPinMuxManager()->SetSource(bus_it->second.mux,
+ bus_it->second.mux);
+ }
+
+ bus_it->second.driver_ = std::move(driver);
+
+ return std::unique_ptr<UartDevice>(new UartDevice(&(bus_it->second)));
+}
+
+} // namespace android
diff --git a/daemon/uart_manager.h b/daemon/uart_manager.h
new file mode 100644
index 0000000..b304ea1
--- /dev/null
+++ b/daemon/uart_manager.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_UART_MANAGER_H_
+#define SYSTEM_PERIPHERALMANAGER_DAEMON_UART_MANAGER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <base/macros.h>
+
+#include "pin_mux_manager.h"
+#include "uart_driver.h"
+
+namespace android {
+
+struct UartSysfs {
+ std::string name;
+ std::string path;
+ std::string mux;
+ std::unique_ptr<UartDriverInterface> driver_;
+};
+
+class UartDevice {
+ public:
+ UartDevice(UartSysfs* uart_device) : uart_device_(uart_device) {}
+ ~UartDevice() { uart_device_->driver_.reset(); }
+
+ int SetBaudrate(uint32_t baudrate) {
+ return uart_device_->driver_->SetBaudrate(baudrate);
+ }
+
+ int Write(const std::vector<uint8_t>& data, uint32_t* bytes_written) {
+ return uart_device_->driver_->Write(data, bytes_written);
+ }
+
+ int Read(std::vector<uint8_t>* data, uint32_t size, uint32_t* bytes_read) {
+ return uart_device_->driver_->Read(data, size, bytes_read);
+ }
+
+ private:
+ UartSysfs* uart_device_;
+};
+
+class UartManager {
+ public:
+ ~UartManager();
+
+ // Get the singleton.
+ static UartManager* GetManager();
+ static void ResetManager();
+
+ // Used by the BSP to tell PMan of an sysfs uart_device.
+ bool RegisterUartDevice(const std::string& name, const std::string& path);
+ bool SetPinMux(const std::string& name, const std::string& mux);
+
+ std::vector<std::string> GetDevicesList();
+ bool HasUartDevice(const std::string& name);
+
+ bool RegisterDriver(std::unique_ptr<UartDriverInfoBase> driver_info);
+
+ std::unique_ptr<UartDevice> OpenUartDevice(const std::string& name);
+
+ private:
+ UartManager();
+
+ std::map<std::string, std::unique_ptr<UartDriverInfoBase>> driver_infos_;
+ std::map<std::string, UartSysfs> uart_devices_;
+
+ DISALLOW_COPY_AND_ASSIGN(UartManager);
+};
+
+} // namespace android
+
+#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_UART_MANAGER_H_
diff --git a/hal/hardware/peripheral_io.h b/hal/hardware/peripheral_io.h
index 1de31ef..624e83b 100644
--- a/hal/hardware/peripheral_io.h
+++ b/hal/hardware/peripheral_io.h
@@ -213,6 +213,30 @@ typedef struct peripheral_registration_cb_t {
int (*register_led_sysfs)(const char* name, const char* sysfs_name);
/**
+ * Register a UART bus.
+ *
+ * Args:
+ * name: Friendly name of the bus.
+ * dev_name: Name of the device in sysfs.
+ *
+ * Returns:
+ * 0 on success, errno on error.
+ */
+ int (*register_uart_bus)(const char* name, const char* dev_name);
+
+ /**
+ * Set the pinmux for a given UART bus.
+ *
+ * Args:
+ * name: Friendly name of the UART bus.
+ * source: Name of the pinmuxing source.
+ *
+ * Returns:
+ * 0 on success, errno on error.
+ */
+ int (*set_uart_pin_mux)(const char* name, const char* source);
+
+ /**
* Register an I2C bus.
*
* Args: