aboutsummaryrefslogtreecommitdiff
path: root/daemon/uart_driver_sysfs.cc
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/uart_driver_sysfs.cc')
-rw-r--r--daemon/uart_driver_sysfs.cc204
1 files changed, 204 insertions, 0 deletions
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