blob: 41e3064a86440bdb1f6a98a9ad0f2931cbec1f3d [file] [log] [blame]
/*
* 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