| /* |
| * 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 |