Project import
diff --git a/peripheralmanager/.clang-format b/peripheralmanager/.clang-format new file mode 120000 index 0000000..f412743 --- /dev/null +++ b/peripheralmanager/.clang-format
@@ -0,0 +1 @@ +../../build/tools/brillo-clang-format \ No newline at end of file
diff --git a/peripheralmanager/Android.mk b/peripheralmanager/Android.mk new file mode 100644 index 0000000..178cb8a --- /dev/null +++ b/peripheralmanager/Android.mk
@@ -0,0 +1,17 @@ +# +# Copyright (C) 2015 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 $(call all-subdir-makefiles)
diff --git a/peripheralmanager/MODULE_LICENSE_APACHE2 b/peripheralmanager/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/peripheralmanager/MODULE_LICENSE_APACHE2
diff --git a/peripheralmanager/NOTICE b/peripheralmanager/NOTICE new file mode 100644 index 0000000..a849a94 --- /dev/null +++ b/peripheralmanager/NOTICE
@@ -0,0 +1,190 @@ + + Copyright (c) 2014-2015, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +
diff --git a/peripheralmanager/README b/peripheralmanager/README new file mode 100644 index 0000000..00d0c95 --- /dev/null +++ b/peripheralmanager/README
@@ -0,0 +1,3 @@ +PeripheralManager + +TODO(leecam): Write this file
diff --git a/peripheralmanager/client/Android.mk b/peripheralmanager/client/Android.mk new file mode 100644 index 0000000..680becc --- /dev/null +++ b/peripheralmanager/client/Android.mk
@@ -0,0 +1,80 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +libperipheralman_CommonCFlags := -Wall -Werror -Wno-unused-parameter +libperipheralman_CommonCFlags += -Wno-sign-promo # for libchrome +libperipheralman_CommonCIncludes := \ + $(LOCAL_PATH)/../common \ + $(LOCAL_PATH)/../include \ + +libperipheralman_CommonSharedLibraries := \ + libbinder \ + libbinderwrapper \ + libbrillo \ + libchrome \ + libutils \ + +# libperipheralman shared library +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libperipheralman +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(libperipheralman_CommonCFlags) +LOCAL_C_INCLUDES := $(libperipheralman_CommonCIncludes) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include +LOCAL_SHARED_LIBRARIES := $(libperipheralman_CommonSharedLibraries) +LOCAL_STATIC_LIBRARIES := libperipheralman_binder +LOCAL_SRC_FILES := \ + gpio_impl.cc \ + i2c_device_impl.cc \ + led_impl.cc \ + peripheral_manager_client_impl.cc \ + spi_device_impl.cc \ + uart_device_impl.cc \ + wrapper.cc \ + +include $(BUILD_SHARED_LIBRARY) + +# libperipheralman_tests executable +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libperipheralman_tests +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(libperipheralman_CommonCFlags) -Wno-sign-compare +LOCAL_C_INCLUDES := $(libperipheralman_CommonCIncludes) +LOCAL_STATIC_LIBRARIES := libgtest libBionicGtestMain \ + libperipheralman_binder \ + libperipheralman_internal_test \ + libgmock \ + +LOCAL_SHARED_LIBRARIES := \ + $(libperipheralman_CommonSharedLibraries) \ + libperipheralman \ + libbinderwrapper_test_support \ + +LOCAL_SRC_FILES := \ + gpio_unittest.cc \ + i2c_unittest.cc \ + led_unittest.cc \ + peripheral_manager_client_unittest.cc \ + spi_unittest.cc \ + uart_unittest.cc \ + +include $(BUILD_NATIVE_TEST)
diff --git a/peripheralmanager/client/gpio_impl.cc b/peripheralmanager/client/gpio_impl.cc new file mode 100644 index 0000000..dfe5f83 --- /dev/null +++ b/peripheralmanager/client/gpio_impl.cc
@@ -0,0 +1,118 @@ +/* + * 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 "gpio_impl.h" + +#include <android-base/unique_fd.h> +#include <binder/Status.h> + +#include "peripheralmanager/constants.h" +#include "peripheralmanager/gpio.h" + +using android::binder::Status; +using android::os::IPeripheralManagerClient; +using android::GpioActiveType; +using android::GpioDirection; +using android::GpioEdgeType; + +bool ActiveTypeFromInt(int type, GpioActiveType* out) { + if (type == ACTIVE_LOW) { + *out = android::kActiveLow; + return true; + } else if (type == ACTIVE_HIGH) { + *out = android::kActiveHigh; + return true; + } + return false; +} + +bool DirectionFromInt(int direction, android::GpioDirection* out) { + switch (direction) { + case DIRECTION_IN: + *out = android::kDirectionIn; + return true; + case DIRECTION_OUT_INITIALLY_HIGH: + *out = android::kDirectionOutInitiallyHigh; + return true; + case DIRECTION_OUT_INITIALLY_LOW: + *out = android::kDirectionOutInitiallyLow; + return true; + } + return false; +} + +bool EdgeTypeFromInt(int type, android::GpioEdgeType* out) { + switch (type) { + case NONE_EDGE: + *out = android::kEdgeNone; + return true; + case RISING_EDGE: + *out = android::kEdgeRising; + return true; + case FALLING_EDGE: + *out = android::kEdgeFalling; + return true; + case BOTH_EDGE: + *out = android::kEdgeBoth; + return true; + } + return false; +} + +GpioImpl::GpioImpl(const std::string name, + android::sp<IPeripheralManagerClient> client) + : name_(name), client_(client) {} + +GpioImpl::~GpioImpl() { + client_->ReleaseGpio(name_); +} + +int GpioImpl::SetDirection(GpioDirection direction) { + return client_->SetGpioDirection(name_, direction).serviceSpecificErrorCode(); +} + +int GpioImpl::SetEdgeTriggerType(GpioEdgeType type) { + return client_->SetGpioEdge(name_, type).serviceSpecificErrorCode(); +} + +int GpioImpl::SetActiveType(GpioActiveType type) { + return client_->SetGpioActiveType(name_, type).serviceSpecificErrorCode(); +} + +int GpioImpl::SetValue(int value) { + return client_->SetGpioValue(name_, value != 0).serviceSpecificErrorCode(); +} + +int GpioImpl::GetValue(int* value) { + bool val = true; + Status ret = client_->GetGpioValue(name_, &val); + if (ret.isOk()) { + *value = val ? 1 : 0; + } + return ret.serviceSpecificErrorCode(); +} + +int GpioImpl::GetPollingFd(int* fd) { + android::base::unique_fd scoped_fd; + Status ret = client_->GetGpioPollingFd(name_, &scoped_fd); + if (ret.isOk()) { + uint8_t buf[2]; + read(scoped_fd.get(), buf, 2); + lseek(scoped_fd.get(), 0, SEEK_SET); + *fd = scoped_fd.release(); + } + return ret.serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/gpio_impl.h b/peripheralmanager/client/gpio_impl.h new file mode 100644 index 0000000..089a4e3 --- /dev/null +++ b/peripheralmanager/client/gpio_impl.h
@@ -0,0 +1,54 @@ +/* + * 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_GPIO_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_GPIO_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> +#include "peripheralmanager/constants.h" + +bool ActiveTypeFromInt(int type, android::GpioActiveType* out); +bool DirectionFromInt(int direction, android::GpioDirection* out); +bool EdgeTypeFromInt(int type, android::GpioEdgeType* out); + +class GpioImpl { + public: + GpioImpl(const std::string name, + android::sp<android::os::IPeripheralManagerClient> client); + + ~GpioImpl(); + + int SetDirection(android::GpioDirection direction); + + int SetEdgeTriggerType(android::GpioEdgeType type); + + int SetActiveType(android::GpioActiveType type); + + int SetValue(int value); + + int GetValue(int* value); + + int GetPollingFd(int* fd); + + private: + std::string name_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_GPIO_IMPL_H_
diff --git a/peripheralmanager/client/gpio_unittest.cc b/peripheralmanager/client/gpio_unittest.cc new file mode 100644 index 0000000..f5b54bc --- /dev/null +++ b/peripheralmanager/client/gpio_unittest.cc
@@ -0,0 +1,155 @@ +/* + * 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 <memory> + +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "gpio_driver_mock.h" +#include "peripheral_manager.h" +#include "peripheralmanager/gpio.h" +#include "peripheralmanager/peripheral_manager_client.h" + +using android::GpioDriverInfo; +using android::GpioDriverInfoBase; +using android::GpioDriverMock; +using android::GpioManager; +using android::PeripheralManager; + +// Base class used to test the Gpio C API. +// As we rely on static, global managers, we cannot run this tests in parallel. +// Please use -j1 when running theses tests or you may see false negatives. +class GpioTest : public android::BinderTestBase { + public: + void SetUp() { + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + GpioManager* man = GpioManager::GetGpioManager(); + man->RegisterDriver(std::unique_ptr<GpioDriverInfoBase>( + new GpioDriverInfo<GpioDriverMock, void*>(nullptr))); + + man->RegisterGpioSysfs("IO1", 1); + man->RegisterGpioSysfs("IO2", 2); + man->RegisterGpioSysfs("IO3", 3); + man->RegisterGpioSysfs("IO4", 4); + man->RegisterGpioSysfs("IO5", 5); + } + + void TearDown() { GpioManager::ResetGpioManager(); } +}; + +// Test that we list the Gpios available correctly. +TEST_F(GpioTest, CanListGpios) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + int ngpios; + char** list = BPeripheralManagerClient_listGpio(client, &ngpios); + + EXPECT_EQ(5, ngpios); + EXPECT_EQ("IO1", std::string(list[0])); + EXPECT_EQ("IO2", std::string(list[1])); + EXPECT_EQ("IO3", std::string(list[2])); + EXPECT_EQ("IO4", std::string(list[3])); + EXPECT_EQ("IO5", std::string(list[4])); + + // Free the list. + for (int i = 0; i < 5; i++) { + free(list[i]); + } + free(list); +} + +// Test that we can open a Gpio and act on it. +TEST_F(GpioTest, CanOpenGpio) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + BGpio* gpio; + EXPECT_EQ(0, BPeripheralManagerClient_openGpio(client, "IO1", &gpio)); + ASSERT_NE(nullptr, gpio); + + // Can set the direction. If the direction is invalid, we fail. + EXPECT_EQ(0, BGpio_setDirection(gpio, DIRECTION_OUT_INITIALLY_HIGH)); + EXPECT_EQ(EINVAL, BGpio_setDirection(gpio, 10)); + + // Can set the value. + EXPECT_EQ(0, BGpio_setValue(gpio, 1)); + + // Can set the active type. If the type is unknown, we fail. + EXPECT_EQ(0, BGpio_setActiveType(gpio, ACTIVE_LOW)); + EXPECT_EQ(EINVAL, BGpio_setActiveType(gpio, 5)); + + EXPECT_EQ(0, BGpio_setDirection(gpio, DIRECTION_IN)); + + // Can read the value from the Gpio. + int value; + EXPECT_EQ(0, BGpio_getValue(gpio, &value)); + + // Setting the value returns an error. + EXPECT_EQ(EREMOTEIO, BGpio_setValue(gpio, 1)); + + // Can set the edge type. If the type is unknown, we fail. + EXPECT_EQ(0, BGpio_setEdgeTriggerType(gpio, RISING_EDGE)); + EXPECT_EQ(EINVAL, BGpio_setEdgeTriggerType(gpio, -1)); + + BGpio_delete(gpio); + BPeripheralManagerClient_delete(client); +} + +// Test that openning an unknown Gpio fails. +TEST_F(GpioTest, OpenningUnknownGpioFails) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + BGpio* gpio = nullptr; + EXPECT_EQ(ENODEV, + BPeripheralManagerClient_openGpio(client, "unknown", &gpio)); + EXPECT_EQ(nullptr, gpio); + + BPeripheralManagerClient_delete(client); +} + +// Test that we track ownership correctly (can't open a Gpio twice). +TEST_F(GpioTest, GpioOnlyOpenedOnce) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + BGpio* gpio1; + BGpio* gpio2; + BGpio* gpio3; + + EXPECT_EQ(0, BPeripheralManagerClient_openGpio(client, "IO1", &gpio1)); + EXPECT_NE(nullptr, gpio1); + + // Can't open the same Gpio. + EXPECT_EQ(EBUSY, BPeripheralManagerClient_openGpio(client, "IO1", &gpio2)); + + // Can open another Gpio. + EXPECT_EQ(0, BPeripheralManagerClient_openGpio(client, "IO3", &gpio3)); + + // Once we delete the struct, the Gpio is released and we can open it. + BGpio_delete(gpio1); + EXPECT_EQ(0, BPeripheralManagerClient_openGpio(client, "IO1", &gpio2)); + + BGpio_delete(gpio2); + BGpio_delete(gpio3); + BPeripheralManagerClient_delete(client); +}
diff --git a/peripheralmanager/client/i2c_device_impl.cc b/peripheralmanager/client/i2c_device_impl.cc new file mode 100644 index 0000000..01bef5c --- /dev/null +++ b/peripheralmanager/client/i2c_device_impl.cc
@@ -0,0 +1,106 @@ +/* + * 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 <vector> + +#include <peripheralmanager/i2c_device.h> + +#include "i2c_device_impl.h" + +using android::sp; +using android::os::IPeripheralManagerClient; +using android::binder::Status; + +I2cDeviceImpl::I2cDeviceImpl(const std::string& name, + uint32_t address, + sp<IPeripheralManagerClient> client) + : name_(name), address_(address), client_(client) {} + +I2cDeviceImpl::~I2cDeviceImpl() { + client_->ReleaseI2cDevice(name_, address_); +} + +int I2cDeviceImpl::Read(void* data, uint32_t len, uint32_t* bytes_read) { + std::vector<uint8_t> read; + Status status = client_->I2cRead( + name_, address_, &read, len, reinterpret_cast<int32_t*>(bytes_read)); + memcpy(data, read.data(), *bytes_read); + return status.serviceSpecificErrorCode(); +} + +int I2cDeviceImpl::ReadRegByte(uint8_t reg, uint8_t* val) { + int32_t tmp_val; + int ret = client_->I2cReadRegByte(name_, address_, reg, &tmp_val) + .serviceSpecificErrorCode(); + if (!ret) { + *val = tmp_val; + } + return ret; +} + +int I2cDeviceImpl::ReadRegWord(uint8_t reg, uint16_t* val) { + int32_t tmp_val; + int ret = client_->I2cReadRegWord(name_, address_, reg, &tmp_val) + .serviceSpecificErrorCode(); + if (!ret) { + *val = tmp_val; + } + return ret; +} + +int I2cDeviceImpl::ReadRegBuffer(uint8_t reg, + void* data, + uint32_t len, + uint32_t* bytes_read) { + std::vector<uint8_t> read(len); + Status status = client_->I2cReadRegBuffer( + name_, address_, reg, &read, len, reinterpret_cast<int32_t*>(bytes_read)); + memcpy(data, read.data(), *bytes_read); + + return status.serviceSpecificErrorCode(); +} + +int I2cDeviceImpl::Write(const void* data, + uint32_t len, + uint32_t* bytes_written) { + const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data); + std::vector<uint8_t> v(bytes, bytes + len); + return client_ + ->I2cWrite(name_, address_, v, reinterpret_cast<int32_t*>(bytes_written)) + .serviceSpecificErrorCode(); +} + +int I2cDeviceImpl::WriteRegByte(uint8_t reg, uint8_t val) { + return client_->I2cWriteRegByte(name_, address_, reg, val) + .serviceSpecificErrorCode(); +} + +int I2cDeviceImpl::WriteRegWord(uint8_t reg, uint16_t val) { + return client_->I2cWriteRegWord(name_, address_, reg, val) + .serviceSpecificErrorCode(); +} + +int I2cDeviceImpl::WriteRegBuffer(uint8_t reg, + const void* data, + uint32_t len, + uint32_t* bytes_written) { + const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data); + std::vector<uint8_t> v(bytes, bytes + len); + return client_ + ->I2cWriteRegBuffer( + name_, address_, reg, v, reinterpret_cast<int32_t*>(bytes_written)) + .serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/i2c_device_impl.h b/peripheralmanager/client/i2c_device_impl.h new file mode 100644 index 0000000..412c662 --- /dev/null +++ b/peripheralmanager/client/i2c_device_impl.h
@@ -0,0 +1,55 @@ +/* + * 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_I2C_DEVICE_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class I2cDeviceImpl { + public: + I2cDeviceImpl(const std::string& bus, + uint32_t address, + android::sp<android::os::IPeripheralManagerClient> client); + + int Read(void* data, uint32_t len, uint32_t* bytes_read); + int ReadRegByte(uint8_t reg, uint8_t* val); + int ReadRegWord(uint8_t reg, uint16_t* val); + int ReadRegBuffer(uint8_t reg, + void* data, + uint32_t len, + uint32_t* bytes_read); + + int Write(const void* data, uint32_t len, uint32_t* bytes_written); + int WriteRegByte(uint8_t reg, uint8_t byte); + int WriteRegWord(uint8_t reg, uint16_t byte); + int WriteRegBuffer(uint8_t reg, + const void* data, + uint32_t len, + uint32_t* bytes_written); + + ~I2cDeviceImpl(); + + private: + std::string name_; + uint32_t address_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_IMPL_H_
diff --git a/peripheralmanager/client/i2c_unittest.cc b/peripheralmanager/client/i2c_unittest.cc new file mode 100644 index 0000000..7e95a99 --- /dev/null +++ b/peripheralmanager/client/i2c_unittest.cc
@@ -0,0 +1,190 @@ +/* + * 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 <memory> + +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "fake_i2c_devices.h" +#include "i2c_driver_i2cdev.h" +#include "peripheral_manager.h" +#include "peripheralmanager/i2c_device.h" +#include "peripheralmanager/peripheral_manager_client.h" + +using android::CharDeviceFactory; +using android::FakeI2cDeviceFactory; +using android::I2cDriverI2cDev; +using android::I2cDriverInfo; +using android::I2cDriverInfoBase; +using android::I2cManager; +using android::PeripheralManager; + +class I2cTest : public android::BinderTestBase { + public: + void SetUp() { + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + I2cManager* man = I2cManager::GetI2cManager(); + man->RegisterDriver(std::unique_ptr<I2cDriverInfoBase>( + new I2cDriverInfo<I2cDriverI2cDev, CharDeviceFactory*>( + &i2c_device_factory_))); + + man->RegisterI2cDevBus("I2C0", 0); + man->RegisterI2cDevBus("I2C1", 1); + } + + void TearDown() { I2cManager::ResetI2cManager(); } + + private: + FakeI2cDeviceFactory i2c_device_factory_; +}; + +// Test that we can list the I2c buses correctly. +TEST_F(I2cTest, ListI2cBuses) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + int nbuses = -1; + char** devices = BPeripheralManagerClient_listI2cBuses(client, &nbuses); + + ASSERT_EQ(2, nbuses); + EXPECT_EQ("I2C0", std::string(devices[0])); + EXPECT_EQ("I2C1", std::string(devices[1])); + + for (int i = 0; i < nbuses; i++) { + free(devices[i]); + } + free(devices); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can open a device and perform basic operations. +TEST_F(I2cTest, OpenDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BI2cDevice* device; + ASSERT_EQ( + 0, BPeripheralManagerClient_openI2cDevice(client, "I2C0", 0x10, &device)); + + std::vector<uint8_t> buffer(40, 42); + + uint32_t count = 0; + + // Can write 20 bytes to the device. + EXPECT_EQ(0, BI2cDevice_write(device, buffer.data(), 20, &count)); + EXPECT_EQ(20, count); + + // Can write bytes and words to specific registers. + EXPECT_EQ(0, BI2cDevice_writeRegByte(device, 8, 60)); + EXPECT_EQ(0, BI2cDevice_writeRegWord(device, 9, 2000)); + + // Can write 20 bytes to a specific register. + count = 0; + EXPECT_EQ(0, + BI2cDevice_writeRegBuffer(device, 10, buffer.data(), 20, &count)); + EXPECT_EQ(20, count); + + uint8_t byte; + uint16_t word; + + // Can read 20 bytes from the device. + buffer.assign(40, 0); + count = 0; + EXPECT_EQ(0, BI2cDevice_read(device, buffer.data(), 20, &count)); + EXPECT_EQ(20, count); + + // Can read bytes and word from the device. + EXPECT_EQ(0, BI2cDevice_readRegByte(device, 8, &byte)); + EXPECT_EQ(60, byte); + + EXPECT_EQ(0, BI2cDevice_readRegWord(device, 9, &word)); + EXPECT_EQ(2000, word); + + // Can read 20 bytes from a specific register. + count = 0; + buffer.assign(40, 0); + EXPECT_EQ(0, BI2cDevice_readRegBuffer(device, 10, buffer.data(), 20, &count)); + EXPECT_EQ(20, count); + for (int i = 0; i < 40; i++) { + EXPECT_EQ(i < 20 ? 42 : 0, buffer[i]); + } + + BI2cDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that we can't open the same device twice. +TEST_F(I2cTest, CantOpenDeviceTwice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BI2cDevice* device1 = nullptr; + BI2cDevice* device2 = nullptr; + BI2cDevice* device3 = nullptr; + BI2cDevice* device4 = nullptr; + + // Can open the device once. + ASSERT_EQ( + 0, + BPeripheralManagerClient_openI2cDevice(client, "I2C0", 0x10, &device1)); + ASSERT_NE(nullptr, device1); + + // Can open a device on the same address on a different bus. + ASSERT_EQ( + 0, + BPeripheralManagerClient_openI2cDevice(client, "I2C1", 0x10, &device2)); + ASSERT_NE(nullptr, device2); + + // Can open another device on the same bus. + ASSERT_EQ( + 0, + BPeripheralManagerClient_openI2cDevice(client, "I2C0", 0x13, &device3)); + ASSERT_NE(nullptr, device3); + + // Can't open a device already in use. + ASSERT_EQ( + EBUSY, + BPeripheralManagerClient_openI2cDevice(client, "I2C0", 0x10, &device4)); + ASSERT_EQ(nullptr, device4); + + // After releasing the device, we can re-open it. + BI2cDevice_delete(device1); + ASSERT_EQ( + 0, + BPeripheralManagerClient_openI2cDevice(client, "I2C0", 0x10, &device4)); + ASSERT_NE(nullptr, device4); + + BI2cDevice_delete(device2); + BI2cDevice_delete(device3); + BI2cDevice_delete(device4); + BPeripheralManagerClient_delete(client); +} + +// Test that we cleanly fail to open an unknown device. +TEST_F(I2cTest, CantOpenUnknownDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BI2cDevice* device = nullptr; + ASSERT_EQ( + ENODEV, + BPeripheralManagerClient_openI2cDevice(client, "I2C5", 0x10, &device)); + ASSERT_EQ(nullptr, device); + + BPeripheralManagerClient_delete(client); +}
diff --git a/peripheralmanager/client/led_impl.cc b/peripheralmanager/client/led_impl.cc new file mode 100644 index 0000000..164cf2b --- /dev/null +++ b/peripheralmanager/client/led_impl.cc
@@ -0,0 +1,51 @@ +/* + * 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 <led_impl.h> + +using android::binder::Status; +using android::os::IPeripheralManagerClient; +using android::sp; + +LedImpl::LedImpl(const std::string& name, sp<IPeripheralManagerClient> client) + : name_(name), client_(client) {} + +LedImpl::~LedImpl() { + client_->ReleaseLed(name_); +} + +int LedImpl::GetBrightness(uint32_t* brightness) { + int val; + Status status = client_->LedGetBrightness(name_, &val); + if (status.isOk()) + *brightness = static_cast<uint32_t>(val); + + return status.serviceSpecificErrorCode(); +} + +int LedImpl::GetMaxBrightness(uint32_t* max_brightness) { + int val; + Status status = client_->LedGetMaxBrightness(name_, &val); + if (status.isOk()) + *max_brightness = static_cast<uint32_t>(val); + + return status.serviceSpecificErrorCode(); +} + +int LedImpl::SetBrightness(uint32_t brightness) { + return client_->LedSetBrightness(name_, brightness) + .serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/led_impl.h b/peripheralmanager/client/led_impl.h new file mode 100644 index 0000000..f848864 --- /dev/null +++ b/peripheralmanager/client/led_impl.h
@@ -0,0 +1,40 @@ +/* + * 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_LED_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_LED_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class LedImpl { + public: + LedImpl(const std::string& name, + android::sp<android::os::IPeripheralManagerClient> client); + ~LedImpl(); + + int GetBrightness(uint32_t* brightness); + int GetMaxBrightness(uint32_t* max_brightness); + int SetBrightness(uint32_t brightness); + + private: + std::string name_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_LED_IMPL_H_
diff --git a/peripheralmanager/client/led_unittest.cc b/peripheralmanager/client/led_unittest.cc new file mode 100644 index 0000000..04c10d4 --- /dev/null +++ b/peripheralmanager/client/led_unittest.cc
@@ -0,0 +1,162 @@ +/* + * 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 <memory> + +#include <base/files/file_util.h> +#include <base/files/scoped_temp_dir.h> +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "led_driver_sysfs.h" +#include "led_manager.h" +#include "peripheral_manager.h" +#include "peripheralmanager/led.h" +#include "peripheralmanager/peripheral_manager_client.h" + +using android::LedDriverInfo; +using android::LedDriverInfoBase; +using android::LedDriverSysfs; +using android::LedManager; +using android::PeripheralManager; + +class LedTest : public android::BinderTestBase { + public: + void SetUp() { + CHECK(dir_.CreateUniqueTempDir()); + + CreateLed("led1", 255, 0); + CreateLed("led2", 1000, 0); + + led_path_prefix_ = dir_.path().value() + "/"; + + // Initialize the peripheral manager with the stub binder wrapper. + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + LedManager* man = LedManager::GetLedManager(); + + // Register the testing version of the LED driver and the fake LEDs. + man->RegisterDriver(std::unique_ptr<LedDriverInfoBase>( + new LedDriverInfo<LedDriverSysfs, std::string*>(&led_path_prefix_))); + + man->RegisterLedSysfs("LED1", "led1"); + man->RegisterLedSysfs("LED2", "led2"); + } + + void CreateLed(const std::string& name, int max_brightness, int brightness) { + base::FilePath led(dir_.path().Append(name)); + base::CreateDirectory(led); + + std::string b_str = std::to_string(brightness); + std::string mb_str = std::to_string(max_brightness); + + ASSERT_EQ( + b_str.size(), + base::WriteFile(led.Append("brightness"), b_str.c_str(), b_str.size())); + ASSERT_EQ(mb_str.size(), + base::WriteFile( + led.Append("max_brightness"), mb_str.c_str(), mb_str.size())); + } + + void TearDown() { LedManager::ResetLedManager(); } + + private: + base::ScopedTempDir dir_; + std::string led_path_prefix_; +}; + +// Test that we can list the available LEDs. +TEST_F(LedTest, CanListLeds) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + int nleds = -1; + char** leds = BPeripheralManagerClient_listLeds(client, &nleds); + + EXPECT_EQ(2, nleds); + EXPECT_EQ("LED1", std::string(leds[0])); + EXPECT_EQ("LED2", std::string(leds[1])); + + for (int i = 0; i < nleds; i++) { + free(leds[i]); + } + free(leds); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can open an LED and act on it. +TEST_F(LedTest, CanOpenLed) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + BLed* led; + + ASSERT_EQ(0, BPeripheralManagerClient_openLed(client, "LED1", &led)); + + uint32_t max_brightness = 0; + EXPECT_EQ(0, BLed_getMaxBrightness(led, &max_brightness)); + EXPECT_EQ(255, max_brightness); + + uint32_t brightness = 0; + EXPECT_EQ(0, BLed_setBrightness(led, 10)); + EXPECT_EQ(0, BLed_getBrightness(led, &brightness)); + EXPECT_EQ(10, brightness); + + BLed_delete(led); + BPeripheralManagerClient_delete(client); +} + +// Test that we can't open an unexisting LED. +TEST_F(LedTest, OpenningUnknownLed) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + BLed* led = nullptr; + EXPECT_EQ(ENODEV, BPeripheralManagerClient_openLed(client, "hello", &led)); + EXPECT_EQ(nullptr, led); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can't open an LED twice. +TEST_F(LedTest, HandleConcurrentAccesses) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + ASSERT_NE(nullptr, client); + + // Can open LED1. + BLed* led1; + EXPECT_EQ(0, BPeripheralManagerClient_openLed(client, "LED1", &led1)); + + // Fails to open it twice. + BLed* led2; + EXPECT_EQ(EBUSY, BPeripheralManagerClient_openLed(client, "LED1", &led2)); + + // Can still open another LED. + BLed* led3; + EXPECT_EQ(0, BPeripheralManagerClient_openLed(client, "LED2", &led3)); + + // Once the LED is released, we can take ownership of it. + BLed_delete(led1); + EXPECT_EQ(0, BPeripheralManagerClient_openLed(client, "LED1", &led2)); + + BLed_delete(led2); + BLed_delete(led3); + BPeripheralManagerClient_delete(client); +}
diff --git a/peripheralmanager/client/peripheral_manager_client_impl.cc b/peripheralmanager/client/peripheral_manager_client_impl.cc new file mode 100644 index 0000000..4fdb731 --- /dev/null +++ b/peripheralmanager/client/peripheral_manager_client_impl.cc
@@ -0,0 +1,102 @@ +/* + * 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 "peripheral_manager_client_impl.h" + +#include <android/os/IPeripheralManager.h> +#include <binderwrapper/binder_wrapper.h> + +using android::binder::Status; + +bool PeripheralManagerClientImpl::Init() { + auto wrapper = android::interface_cast<android::os::IPeripheralManager>( + android::BinderWrapper::GetOrCreateInstance()->GetService( + "android.os.IPeripheralManager")); + lifeline_ = new android::BBinder; + + return wrapper->GetClient(lifeline_, &client_).isOk(); +} + +int PeripheralManagerClientImpl::OpenGpio(const std::string& name, + std::unique_ptr<GpioImpl>* gpio) { + Status status = client_->OpenGpio(name); + if (status.isOk()) { + gpio->reset(new GpioImpl(name, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListGpio(std::vector<std::string>* gpios) { + Status status = client_->ListGpio(gpios); + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::OpenSpiDevice( + const std::string& name, + std::unique_ptr<SpiDeviceImpl>* device) { + Status status = client_->OpenSpiDevice(name); + if (status.isOk()) { + device->reset(new SpiDeviceImpl(name, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListSpiBuses(std::vector<std::string>* buses) { + Status status = client_->ListSpiBuses(buses); + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListLeds(std::vector<std::string>* leds) { + return client_->ListLeds(leds).serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::OpenLed(const std::string& name, + std::unique_ptr<LedImpl>* led) { + Status status = client_->OpenLed(name); + if (status.isOk()) { + led->reset(new LedImpl(name, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::OpenI2cDevice( + const std::string& name, + uint32_t address, + std::unique_ptr<I2cDeviceImpl>* device) { + Status status = client_->OpenI2cDevice(name, address); + if (status.isOk()) { + device->reset(new I2cDeviceImpl(name, address, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListI2cBuses(std::vector<std::string>* buses) { + return client_->ListI2cBuses(buses).serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::OpenUartDevice( + const std::string& name, std::unique_ptr<UartDeviceImpl>* device) { + Status status = client_->OpenUartDevice(name); + if (status.isOk()) { + device->reset(new UartDeviceImpl(name, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListUartDevices( + std::vector<std::string>* list) { + return client_->ListUartDevices(list).serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/peripheral_manager_client_impl.h b/peripheralmanager/client/peripheral_manager_client_impl.h new file mode 100644 index 0000000..aba4739 --- /dev/null +++ b/peripheralmanager/client/peripheral_manager_client_impl.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_PERIPHERAL_MANAGER_CLIENT_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_PERIPHERAL_MANAGER_CLIENT_IMPL_H_ + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +#include "gpio_impl.h" +#include "i2c_device_impl.h" +#include "led_impl.h" +#include "spi_device_impl.h" +#include "uart_device_impl.h" + +class PeripheralManagerClientImpl { + public: + PeripheralManagerClientImpl() = default; + + bool Init(); + + int OpenGpio(const std::string& name, std::unique_ptr<GpioImpl>* gpio); + int ListGpio(std::vector<std::string>* gpios); + + int OpenSpiDevice(const std::string& name, + std::unique_ptr<SpiDeviceImpl>* device); + int ListSpiBuses(std::vector<std::string>* buses); + + int OpenLed(const std::string& name, std::unique_ptr<LedImpl>* device); + int ListLeds(std::vector<std::string>* leds); + + int OpenI2cDevice(const std::string& name, + uint32_t address, + std::unique_ptr<I2cDeviceImpl>* device); + int ListI2cBuses(std::vector<std::string>* buses); + + int OpenUartDevice(const std::string& name, + std::unique_ptr<UartDeviceImpl>* device); + int ListUartDevices(std::vector<std::string>* buses); + + private: + android::sp<android::os::IPeripheralManagerClient> client_; + android::sp<android::IBinder> lifeline_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_PERIPHERAL_MANAGER_CLIENT_IMPL_H_
diff --git a/peripheralmanager/client/peripheral_manager_client_unittest.cc b/peripheralmanager/client/peripheral_manager_client_unittest.cc new file mode 100644 index 0000000..e75af24 --- /dev/null +++ b/peripheralmanager/client/peripheral_manager_client_unittest.cc
@@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 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 <peripheralmanager/peripheral_manager_client.h> + +#include "gtest/gtest.h" + +namespace android { + +TEST(PeripheralManagerClient, Init) { +} + +} // namespace android
diff --git a/peripheralmanager/client/spi_device_impl.cc b/peripheralmanager/client/spi_device_impl.cc new file mode 100644 index 0000000..d9bab6d --- /dev/null +++ b/peripheralmanager/client/spi_device_impl.cc
@@ -0,0 +1,84 @@ +/* + * 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 <vector> + +#include <peripheralmanager/spi_device.h> + +#include "spi_device_impl.h" + +using android::sp; +using android::os::IPeripheralManagerClient; +using android::binder::Status; + +SpiDeviceImpl::SpiDeviceImpl(const std::string& name, + sp<IPeripheralManagerClient> client) + : name_(name), client_(client) {} + +SpiDeviceImpl::~SpiDeviceImpl() { + client_->ReleaseSpiDevice(name_); +} + +int SpiDeviceImpl::WriteByte(uint8_t byte) { + return client_->SpiDeviceWriteByte(name_, byte).serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::WriteBuffer(const uint8_t* data, size_t len) { + std::vector<uint8_t> v(data, data + len); + return client_->SpiDeviceWriteBuffer(name_, v).serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::Transfer(const uint8_t* tx_data, + uint8_t* rx_data, + size_t len) { + std::unique_ptr<std::vector<uint8_t>> sent; + std::unique_ptr<std::vector<uint8_t>> received; + + if (tx_data == nullptr) + return EINVAL; + + sent.reset(new std::vector<uint8_t>(tx_data, tx_data + len)); + + Status status = client_->SpiDeviceTransfer(name_, sent, &received, len); + if (status.isOk() && rx_data) + memcpy(rx_data, received->data(), len); + return status.serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::SetFrequency(uint32_t freq_hz) { + return client_->SpiDeviceSetFrequency(name_, freq_hz) + .serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::SetMode(int mode) { + return client_->SpiDeviceSetMode(name_, mode).serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::SetBitJustification(int justification) { + return client_ + ->SpiDeviceSetBitJustification(name_, justification == SPI_LSB_FIRST) + .serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::SetBitsPerWord(uint32_t bits_per_word) { + return client_->SpiDeviceSetBitsPerWord(name_, bits_per_word) + .serviceSpecificErrorCode(); +} + +int SpiDeviceImpl::SetDelay(uint16_t delay_usecs) { + return client_->SpiDeviceSetDelay(name_, delay_usecs) + .serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/spi_device_impl.h b/peripheralmanager/client/spi_device_impl.h new file mode 100644 index 0000000..ed076d5 --- /dev/null +++ b/peripheralmanager/client/spi_device_impl.h
@@ -0,0 +1,52 @@ +/* + * 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_SPI_DEVICE_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_SPI_DEVICE_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class SpiDeviceImpl { + public: + SpiDeviceImpl(const std::string& bus, + android::sp<android::os::IPeripheralManagerClient> client); + ~SpiDeviceImpl(); + + int WriteByte(uint8_t byte); + + int WriteBuffer(const uint8_t* data, size_t len); + + int Transfer(const uint8_t* tx_data, uint8_t* rx_data, size_t len); + + int SetFrequency(uint32_t speed_hz); + + int SetMode(int mode); + + int SetBitJustification(int bit_justification); + + int SetBitsPerWord(uint32_t bits_per_word); + + int SetDelay(uint16_t delay_usecs); + + private: + std::string name_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_SPI_DEVICE_IMPL_H_
diff --git a/peripheralmanager/client/spi_unittest.cc b/peripheralmanager/client/spi_unittest.cc new file mode 100644 index 0000000..cc8a3fb --- /dev/null +++ b/peripheralmanager/client/spi_unittest.cc
@@ -0,0 +1,200 @@ +/* + * 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 <memory> + +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "fake_devices.h" +#include "peripheral_manager.h" +#include "peripheralmanager/peripheral_manager_client.h" +#include "peripheralmanager/spi_device.h" +#include "spi_driver_spidev.h" + +using android::CharDeviceFactory; +using android::FakeDeviceFactory; +using android::SpiDriverInfo; +using android::SpiDriverInfoBase; +using android::SpiDriverSpiDev; +using android::SpiManager; +using android::PeripheralManager; + +// Base class used to test the Spi C API. +// As we rely on static, global managers, we cannot run this tests in parallel. +// Please use -j1 when running theses tests or you may see false negatives. +class SpiTest : public android::BinderTestBase { + public: + void SetUp() { + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + SpiManager* man = SpiManager::GetSpiManager(); + + man->GetSpiDevBuses(); + man->RegisterDriver(std::unique_ptr<SpiDriverInfoBase>( + new SpiDriverInfo<SpiDriverSpiDev, CharDeviceFactory*>( + &device_factory_))); + + man->RegisterSpiDevBus("SPI_A", 1, 0); + man->RegisterSpiDevBus("SPI_B", 1, 1); + } + + void TearDown() { SpiManager::ResetSpiManager(); } + + private: + FakeDeviceFactory device_factory_; +}; + +// Test that we can list the available devices. +TEST_F(SpiTest, ListSpiDevices) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + int ndev = -1; + char** devices = BPeripheralManagerClient_listSpiBuses(client, &ndev); + + ASSERT_EQ(2, ndev); + EXPECT_EQ("SPI_A", std::string(devices[0])); + EXPECT_EQ("SPI_B", std::string(devices[1])); + + for (int i = 0; i < ndev; i++) { + free(devices[i]); + } + free(devices); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can open a device and use the basic functions. +TEST_F(SpiTest, OpenSpiDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BSpiDevice* device = nullptr; + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device)); + ASSERT_NE(nullptr, device); + + EXPECT_EQ(0, BSpiDevice_writeByte(device, 0x10)); + + std::vector<uint8_t> v = {1, 2, 3, 4}; + EXPECT_EQ(0, BSpiDevice_writeBuffer(device, v.data(), v.size())); + + BSpiDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that the transfer function behave correctly. +TEST_F(SpiTest, Transfer) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BSpiDevice* device = nullptr; + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device)); + ASSERT_NE(nullptr, device); + + // Passing an empty return pointer is valid. + std::vector<uint8_t> v = {0, 0, 0, 0}; + uint8_t received[4]; + EXPECT_EQ(0, BSpiDevice_transfer(device, v.data(), nullptr, v.size())); + + // Passing an empty send pointer is invalid. + EXPECT_EQ(EINVAL, BSpiDevice_transfer(device, nullptr, &received, 4)); + + BSpiDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that we can configure the device correctly and that we fail cleanly if +// the configuration is incorrect. +TEST_F(SpiTest, SetConfiguration) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BSpiDevice* device = nullptr; + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device)); + ASSERT_NE(nullptr, device); + + // We can set the mode and detect an invalid mode. + EXPECT_EQ(0, BSpiDevice_setMode(device, SPI_MODE0)); + EXPECT_EQ(0, BSpiDevice_setMode(device, SPI_MODE1)); + EXPECT_EQ(0, BSpiDevice_setMode(device, SPI_MODE2)); + EXPECT_EQ(0, BSpiDevice_setMode(device, SPI_MODE3)); + EXPECT_EQ(EINVAL, BSpiDevice_setMode(device, SPI_MODE3 + 1)); + + // We can set the bit justification and detect an invalid justification. + EXPECT_EQ(0, BSpiDevice_setBitJustification(device, SPI_LSB_FIRST)); + EXPECT_EQ(0, BSpiDevice_setBitJustification(device, SPI_MSB_FIRST)); + EXPECT_EQ(EINVAL, BSpiDevice_setBitJustification(device, SPI_MSB_FIRST + 1)); + + // We can set the frequency. + EXPECT_EQ(0, BSpiDevice_setFrequency(device, 100000)); + + // We can set the number of bits per word. + EXPECT_EQ(0, BSpiDevice_setBitsPerWord(device, 16)); + + // We can set the delay between transfers. + EXPECT_EQ(0, BSpiDevice_setDelay(device, 100)); + + BSpiDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that we fail when trying to open the same device twice. +TEST_F(SpiTest, CantOpenDeviceTwice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BSpiDevice* device1 = nullptr; + BSpiDevice* device2 = nullptr; + BSpiDevice* device3 = nullptr; + + // Can open SPI_A once. + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device1)); + ASSERT_NE(nullptr, device1); + + // The device can't be opened a second time because it is busy. + ASSERT_EQ(EBUSY, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device2)); + ASSERT_EQ(nullptr, device2); + + // Can open another device. + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_B", &device3)); + + // Once released, we can re-open the device. + BSpiDevice_delete(device1); + ASSERT_EQ(0, + BPeripheralManagerClient_openSpiDevice(client, "SPI_A", &device2)); + + BSpiDevice_delete(device2); + BSpiDevice_delete(device3); + BPeripheralManagerClient_delete(client); +} + +// Test that we fail when trying to open an unknown device. +TEST_F(SpiTest, CantOpenUnknownDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BSpiDevice* device = nullptr; + ASSERT_EQ( + ENODEV, + BPeripheralManagerClient_openSpiDevice(client, "SPI_UNKOWN", &device)); + ASSERT_EQ(nullptr, device); + + BPeripheralManagerClient_delete(client); +}
diff --git a/peripheralmanager/client/uart_device_impl.cc b/peripheralmanager/client/uart_device_impl.cc new file mode 100644 index 0000000..becfd62 --- /dev/null +++ b/peripheralmanager/client/uart_device_impl.cc
@@ -0,0 +1,57 @@ +/* + * 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_device_impl.h" + +#include <binder/Status.h> + +using android::binder::Status; + +UartDeviceImpl::UartDeviceImpl( + const std::string& name, + android::sp<android::os::IPeripheralManagerClient> client) + : name_(name), client_(client) {} + +UartDeviceImpl::~UartDeviceImpl() { + client_->ReleaseUartDevice(name_); +} + +int UartDeviceImpl::SetBaudrate(uint32_t baudrate) { + return client_->SetUartDeviceBaudrate(name_, baudrate) + .serviceSpecificErrorCode(); +} + +int UartDeviceImpl::Write(const void* data, + uint32_t size, + uint32_t* bytes_written) { + const uint8_t* d = reinterpret_cast<const uint8_t*>(data); + return client_ + ->UartDeviceWrite(name_, + std::vector<uint8_t>(d, d + size), + reinterpret_cast<int32_t*>(bytes_written)) + .serviceSpecificErrorCode(); +} + +int UartDeviceImpl::Read(void* data, uint32_t size, uint32_t* bytes_read) { + std::vector<uint8_t> v; + Status status = client_->UartDeviceRead( + name_, &v, size, reinterpret_cast<int32_t*>(bytes_read)); + if (status.isOk()) { + memcpy(data, v.data(), *bytes_read); + } + + return status.serviceSpecificErrorCode(); +}
diff --git a/peripheralmanager/client/uart_device_impl.h b/peripheralmanager/client/uart_device_impl.h new file mode 100644 index 0000000..72d5d4a --- /dev/null +++ b/peripheralmanager/client/uart_device_impl.h
@@ -0,0 +1,43 @@ +/* + * 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_UART_DEVICE_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_UART_DEVICE_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class UartDeviceImpl { + public: + UartDeviceImpl(const std::string& name, + android::sp<android::os::IPeripheralManagerClient> client); + + ~UartDeviceImpl(); + + int SetBaudrate(uint32_t baudrate); + + int Write(const void* data, uint32_t size, uint32_t* bytes_written); + + int Read(void* data, uint32_t size, uint32_t* bytes_read); + + private: + std::string name_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_UART_DEVICE_IMPL_H_
diff --git a/peripheralmanager/client/uart_unittest.cc b/peripheralmanager/client/uart_unittest.cc new file mode 100644 index 0000000..ff46433 --- /dev/null +++ b/peripheralmanager/client/uart_unittest.cc
@@ -0,0 +1,151 @@ +/* + * 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 <memory> + +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "fake_devices.h" +#include "peripheral_manager.h" +#include "peripheralmanager/peripheral_manager_client.h" +#include "peripheralmanager/uart_device.h" +#include "uart_driver_sysfs.h" + +using android::CharDeviceFactory; +using android::FakeDeviceFactory; +using android::UartDriverInfo; +using android::UartDriverInfoBase; +using android::UartDriverSysfs; +using android::UartManager; +using android::PeripheralManager; + +// Base class used to test the Uart C API. +// As we rely on static, global managers, we cannot run this tests in parallel. +// Please use -j1 when running theses tests or you may see false negatives. +class UartTest : public android::BinderTestBase { + public: + void SetUp() { + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + UartManager* man = UartManager::GetManager(); + + man->RegisterDriver(std::unique_ptr<UartDriverInfoBase>( + new UartDriverInfo<UartDriverSysfs, CharDeviceFactory*>( + &device_factory_))); + + man->RegisterUartDevice("UART0", "/dev/ttyuart0"); + } + + void TearDown() { UartManager::ResetManager(); } + + private: + FakeDeviceFactory device_factory_; +}; + +// Test that we can list the available devices. +TEST_F(UartTest, ListDevices) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + int n = 0; + char** list = BPeripheralManagerClient_listUartDevices(client, &n); + + ASSERT_EQ(1, n); + ASSERT_EQ("UART0", std::string(list[0])); + + free(list[0]); + free(list); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can open a uart device and set the baudrate. +TEST_F(UartTest, OpenDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ(0, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device)); + + // Can set a valid baudrate. + ASSERT_EQ(0, BUartDevice_setBaudrate(device, 115200)); + + // Setting an invalid baudrate should return an error. + ASSERT_EQ(EINVAL, BUartDevice_setBaudrate(device, 12345)); + + BUartDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that we can detect when a device is accessed twice and report an +// appropriate error. +TEST_F(UartTest, HandlesConflict) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device_a; + BUartDevice* device_b; + + // Can open UART0 once. + ASSERT_EQ( + 0, BPeripheralManagerClient_openUartDevice(client, "UART0", &device_a)); + + // Can't open it twice. + ASSERT_EQ( + EBUSY, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device_b)); + + // Can open it again once closed. + BUartDevice_delete(device_a); + ASSERT_EQ( + 0, BPeripheralManagerClient_openUartDevice(client, "UART0", &device_b)); + + BUartDevice_delete(device_b); + BPeripheralManagerClient_delete(client); +} + +// Test that we report the right error when trying to open an unknown device. +TEST_F(UartTest, UnknownDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ( + ENODEV, + BPeripheralManagerClient_openUartDevice(client, "unknown", &device)); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can read and write to a device. +TEST_F(UartTest, ReadWrite) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ(0, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device)); + + char buf[40]; + uint32_t nwritten; + EXPECT_EQ(0, BUartDevice_write(device, buf, 40, &nwritten)); + + uint32_t nread; + EXPECT_EQ(0, BUartDevice_read(device, buf, 40, &nread)); + + BUartDevice_delete(device); + BPeripheralManagerClient_delete(client); +}
diff --git a/peripheralmanager/client/wrapper.cc b/peripheralmanager/client/wrapper.cc new file mode 100644 index 0000000..f9cc3dc --- /dev/null +++ b/peripheralmanager/client/wrapper.cc
@@ -0,0 +1,383 @@ +/* + * 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 <utils/StrongPointer.h> +#include <memory> + +#include "gpio_impl.h" +#include "led_impl.h" +#include "peripheral_manager_client_impl.h" +#include "peripheralmanager/peripheral_manager_client.h" +#include "spi_device_impl.h" +#include "uart_device_impl.h" + +namespace { + +// This is horrible. Get rid of it!!! +static char** ConvertStringVectorToC(const std::vector<std::string>& strings) { + char** c_strings = (char**)malloc(strings.size() * sizeof(*c_strings)); + for (size_t i = 0; i < strings.size(); i++) { + c_strings[i] = (char*)malloc(strings[i].size() + 1); + memset(c_strings[i], 0, strings[i].size() + 1); + strcpy(c_strings[i], strings[i].c_str()); + } + return c_strings; +} + +} // namespace + +struct BPeripheralManagerClient { + PeripheralManagerClientImpl* impl; +}; + +struct BGpio { + GpioImpl* impl; +}; + +struct BSpiDevice { + SpiDeviceImpl* impl; +}; + +struct BLed { + LedImpl* impl; +}; + +struct BI2cDevice { + I2cDeviceImpl* impl; +}; + +struct BUartDevice { + UartDeviceImpl* impl; +}; + +BPeripheralManagerClient* BPeripheralManagerClient_new() { + std::unique_ptr<PeripheralManagerClientImpl> impl( + new PeripheralManagerClientImpl); + if (impl->Init()) { + return new BPeripheralManagerClient{impl.release()}; + } + + return NULL; +} + +void BPeripheralManagerClient_delete(BPeripheralManagerClient* client) { + delete client->impl; + delete client; +} + +// GPIO API +char** BPeripheralManagerClient_listGpio(const BPeripheralManagerClient* client, + int* num_gpio) { + std::vector<std::string> gpios; + client->impl->ListGpio(&gpios); + *num_gpio = gpios.size(); + return ConvertStringVectorToC(gpios); +} + +int BPeripheralManagerClient_openGpio(const BPeripheralManagerClient* client, + const char* name, + BGpio** gpio) { + std::unique_ptr<GpioImpl> tmp; + int ret = client->impl->OpenGpio(name, &tmp); + if (!ret) { + *gpio = new BGpio{tmp.release()}; + } + return ret; +} + +int BGpio_setDirection(const BGpio* gpio, int direction) { + android::GpioDirection dir; + if (!DirectionFromInt(direction, &dir)) + return EINVAL; + + return gpio->impl->SetDirection(dir); +} + +int BGpio_setEdgeTriggerType(const BGpio* gpio, int type) { + android::GpioEdgeType t; + if (!EdgeTypeFromInt(type, &t)) + return EINVAL; + + return gpio->impl->SetEdgeTriggerType(t); +} + +int BGpio_setActiveType(const BGpio* gpio, int type) { + android::GpioActiveType t; + if (!ActiveTypeFromInt(type, &t)) + return EINVAL; + + return gpio->impl->SetActiveType(t); +} + +int BGpio_setValue(const BGpio* gpio, int value) { + return gpio->impl->SetValue(value); +} + +int BGpio_getValue(const BGpio* gpio, int* value) { + return gpio->impl->GetValue(value); +} + +int BGpio_getPollingFd(const BGpio* gpio, int* fd) { + return gpio->impl->GetPollingFd(fd); +} + +int BGpio_ackInterruptEvent(int fd) { + uint8_t buf[2]; + lseek(fd, 0, SEEK_SET); + read(fd, buf, 2); + return 0; +} + +void BGpio_delete(BGpio* gpio) { + delete gpio->impl; + delete gpio; +} + +// SPI API +char** BPeripheralManagerClient_listSpiBuses( + const BPeripheralManagerClient* client, + int* num_spi_buses) { + std::vector<std::string> list; + client->impl->ListSpiBuses(&list); + *num_spi_buses = list.size(); + return ConvertStringVectorToC(list); +} + +int BPeripheralManagerClient_openSpiDevice( + const BPeripheralManagerClient* client, + const char* name, + BSpiDevice** dev) { + std::unique_ptr<SpiDeviceImpl> impl; + int ret = client->impl->OpenSpiDevice(name, &impl); + if (impl) { + *dev = new BSpiDevice{impl.release()}; + } + + return ret; +} + +int BSpiDevice_writeByte(const BSpiDevice* device, uint8_t val) { + return device->impl->WriteByte(val); +} + +int BSpiDevice_writeBuffer(const BSpiDevice* device, + const void* data, + size_t len) { + return device->impl->WriteBuffer(static_cast<const uint8_t*>(data), len); +} + +int BSpiDevice_transfer(const BSpiDevice* device, + const void* tx_data, + void* rx_data, + size_t len) { + return device->impl->Transfer(static_cast<const uint8_t*>(tx_data), + static_cast<uint8_t*>(rx_data), len); +} + +int BSpiDevice_setFrequency(const BSpiDevice* device, uint32_t freq_hz) { + return device->impl->SetFrequency(freq_hz); +} + +int BSpiDevice_setMode(const BSpiDevice* device, int mode) { + if (mode == SPI_MODE0 || mode == SPI_MODE1 || mode == SPI_MODE2 || + mode == SPI_MODE3) { + return device->impl->SetMode(mode); + } + return EINVAL; +} + +int BSpiDevice_setBitJustification(const BSpiDevice* device, + int bit_justification) { + if (bit_justification == SPI_LSB_FIRST || + bit_justification == SPI_MSB_FIRST) { + return device->impl->SetBitJustification(bit_justification); + } + return EINVAL; +} + +int BSpiDevice_setBitsPerWord(const BSpiDevice* device, uint8_t bits_per_word) { + return device->impl->SetBitsPerWord(bits_per_word); +} + +int BSpiDevice_setDelay(const BSpiDevice* device, uint16_t delay_usecs) { + return device->impl->SetDelay(delay_usecs); +} + +void BSpiDevice_delete(BSpiDevice* device) { + delete device->impl; + delete device; +} + +char** BPeripheralManagerClient_listLeds(const BPeripheralManagerClient* client, + int* num_leds) { + std::vector<std::string> list; + client->impl->ListLeds(&list); + *num_leds = list.size(); + return ConvertStringVectorToC(list); +} + +int BPeripheralManagerClient_openLed(const BPeripheralManagerClient* client, + const char* name, + BLed** led) { + std::unique_ptr<LedImpl> impl; + int ret = client->impl->OpenLed(name, &impl); + if (!ret) + *led = new BLed{impl.release()}; + + return ret; +} + +int BLed_setBrightness(const BLed* led, uint32_t brightness) { + return led->impl->SetBrightness(brightness); +} + +int BLed_getBrightness(const BLed* led, uint32_t* brightness) { + return led->impl->GetBrightness(brightness); +} + +int BLed_getMaxBrightness(const BLed* led, uint32_t* max_brightness) { + return led->impl->GetMaxBrightness(max_brightness); +} + +void BLed_delete(BLed* led) { + delete led->impl; + delete led; +} + +// I2C API +char** BPeripheralManagerClient_listI2cBuses( + const BPeripheralManagerClient* client, int* num_i2c_buses) { + std::vector<std::string> list; + client->impl->ListI2cBuses(&list); + *num_i2c_buses = list.size(); + return ConvertStringVectorToC(list); +} + +int BPeripheralManagerClient_openI2cDevice( + const BPeripheralManagerClient* client, + const char* name, + uint32_t address, + BI2cDevice** dev) { + std::unique_ptr<I2cDeviceImpl> impl; + int ret = client->impl->OpenI2cDevice(name, address, &impl); + if (ret == 0) { + *dev = new BI2cDevice{impl.release()}; + } + + return ret; +} + +int BI2cDevice_read(const BI2cDevice* device, + void* data, + uint32_t len, + uint32_t* bytes_read) { + return device->impl->Read(data, len, bytes_read); +} + +int BI2cDevice_readRegByte(const BI2cDevice* device, + uint8_t reg, + uint8_t* val) { + return device->impl->ReadRegByte(reg, val); +} + +int BI2cDevice_readRegWord(const BI2cDevice* device, + uint8_t reg, + uint16_t* val) { + return device->impl->ReadRegWord(reg, val); +} + +int BI2cDevice_readRegBuffer(const BI2cDevice* device, + uint8_t reg, + void* data, + uint32_t len, + uint32_t* bytes_read) { + return device->impl->ReadRegBuffer(reg, data, len, bytes_read); +} + +int BI2cDevice_write(const BI2cDevice* device, + const void* data, + uint32_t len, + uint32_t* bytes_written) { + return device->impl->Write(data, len, bytes_written); +} + +int BI2cDevice_writeRegByte(const BI2cDevice* device, + uint8_t reg, + uint8_t val) { + return device->impl->WriteRegByte(reg, val); +} + +int BI2cDevice_writeRegWord(const BI2cDevice* device, + uint8_t reg, + uint16_t val) { + return device->impl->WriteRegWord(reg, val); +} + +int BI2cDevice_writeRegBuffer(const BI2cDevice* device, + uint8_t reg, + const void* data, + uint32_t len, + uint32_t* bytes_written) { + return device->impl->WriteRegBuffer(reg, data, len, bytes_written); +} + +void BI2cDevice_delete(BI2cDevice* device) { + delete device->impl; + delete device; +} + +char** BPeripheralManagerClient_listUartDevices( + const BPeripheralManagerClient* client, int* num_uart_devices) { + std::vector<std::string> list; + client->impl->ListUartDevices(&list); + *num_uart_devices = list.size(); + return ConvertStringVectorToC(list); +} + +int BPeripheralManagerClient_openUartDevice( + const BPeripheralManagerClient* client, + const char* name, + BUartDevice** device) { + std::unique_ptr<UartDeviceImpl> impl; + int ret = client->impl->OpenUartDevice(name, &impl); + if (ret == 0) { + *device = new BUartDevice{impl.release()}; + } + return ret; +} + +int BUartDevice_setBaudrate(const BUartDevice* device, uint32_t baudrate) { + return device->impl->SetBaudrate(baudrate); +} + +int BUartDevice_write(const BUartDevice* device, + const void* data, + uint32_t size, + uint32_t* bytes_written) { + return device->impl->Write(data, size, bytes_written); +} + +int BUartDevice_read(const BUartDevice* device, + void* data, + uint32_t size, + uint32_t* bytes_read) { + return device->impl->Read(data, size, bytes_read); +} + +void BUartDevice_delete(BUartDevice* device) { + delete device->impl; + delete device; +}
diff --git a/peripheralmanager/common/peripheralmanager/constants.h b/peripheralmanager/common/peripheralmanager/constants.h new file mode 100644 index 0000000..d30a28f --- /dev/null +++ b/peripheralmanager/common/peripheralmanager/constants.h
@@ -0,0 +1,50 @@ +/* + * 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_PERIPHERALMANAGER_CONSTANTS_H_ +#define SYSTEM_PERIPHERALMANAGER_PERIPHERALMANAGER_CONSTANTS_H_ + +namespace android { + +enum GpioEdgeType { + kEdgeNone, + kEdgeRising, + kEdgeFalling, + kEdgeBoth, +}; + +enum GpioDirection { + kDirectionIn, + kDirectionOutInitiallyHigh, + kDirectionOutInitiallyLow, +}; + +enum GpioActiveType { + kActiveLow, + kActiveHigh, +}; + +// The SPI modes are the same as the ones defined by the linux kernel. +enum SpiMode { + kMode0, + kMode1, + kMode2, + kMode3, +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_PERIPHERALMANAGER_CONSTANTS_H_
diff --git a/peripheralmanager/daemon/Android.mk b/peripheralmanager/daemon/Android.mk new file mode 100644 index 0000000..935ee62 --- /dev/null +++ b/peripheralmanager/daemon/Android.mk
@@ -0,0 +1,141 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +peripheralman_CommonCFlags := -Wall -Werror -Wno-unused-parameter +peripheralman_CommonCFlags += -Wno-sign-promo # for libchrome +peripheralman_CommonCIncludes := \ + $(LOCAL_PATH)/../common \ + $(LOCAL_PATH)/../include \ + external/gtest/include \ + +peripheralman_CommonSharedLibraries := \ + libbinder \ + libbinderwrapper \ + libchrome \ + libutils \ + libhardware \ + +libperipheralman_internal_CommonSources := \ + char_device.cc \ + gpio_driver_sysfs.cc \ + gpio_manager.cc \ + i2c_driver_i2cdev.cc \ + i2c_manager.cc \ + led_driver_sysfs.cc \ + led_manager.cc \ + peripheral_manager.cc \ + peripheral_manager_client.cc \ + pin_mux_manager.cc \ + spi_driver_spidev.cc \ + spi_manager.cc \ + uart_driver_sysfs.cc \ + uart_manager.cc \ + +# peripheralman executable +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := peripheralman +LOCAL_REQUIRED_MODULES := peripheralman.rc +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(peripheralman_CommonCFlags) +LOCAL_C_INCLUDES := $(peripheralman_CommonCIncludes) + +LOCAL_STATIC_LIBRARIES := \ + libperipheralman_internal \ + libperipheralman_binder \ + peripheral_manager_hal_headers \ + +LOCAL_SHARED_LIBRARIES := \ + $(peripheralman_CommonSharedLibraries) \ + libbrillo \ + libbrillo-binder \ + +LOCAL_SRC_FILES := main.cc +LOCAL_INIT_RC := peripheralman.rc +include $(BUILD_EXECUTABLE) + +# libperipheralman_internal static lib +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libperipheralman_internal +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(peripheralman_CommonCFlags) +LOCAL_C_INCLUDES := $(peripheralman_CommonCIncludes) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include +LOCAL_STATIC_LIBRARIES := \ + libperipheralman_binder \ + peripheral_manager_hal_headers \ + +LOCAL_SHARED_LIBRARIES := \ + $(peripheralman_CommonSharedLibraries) \ + +LOCAL_SRC_FILES := $(libperipheralman_internal_CommonSources) +include $(BUILD_STATIC_LIBRARY) + +# libperipheral_internal_test static lib used to test the client. +# =============================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libperipheralman_internal_test +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(peripheralman_CommonCFlags) +LOCAL_C_INCLUDES := $(peripheralman_CommonCIncludes) +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../hal \ + +LOCAL_STATIC_LIBRARIES := \ + libperipheralman_binder \ + peripheral_manager_hal_headers \ + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libbinderwrapper_test_support \ + libchrome \ + libutils \ + libhardware \ + +LOCAL_SRC_FILES := $(libperipheralman_internal_CommonSources) \ + fake_devices.cc \ + fake_i2c_devices.cc \ + +include $(BUILD_STATIC_LIBRARY) + +# peripheralman unit tests +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := peripheralman_unittests +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := $(peripheralman_CommonCFlags) +LOCAL_C_INCLUDES := $(peripheralman_CommonCIncludes) +LOCAL_STATIC_LIBRARIES := libperipheralman_internal \ + peripheral_manager_hal_headers \ + +LOCAL_SHARED_LIBRARIES := \ + libchrome \ + +LOCAL_SRC_FILES := \ + fake_devices.cc \ + fake_i2c_devices.cc \ + gpio_manager_unittest.cc \ + pin_mux_manager_unittest.cc \ + spi_manager_unittest.cc \ + +include $(BUILD_NATIVE_TEST)
diff --git a/peripheralmanager/daemon/char_device.cc b/peripheralmanager/daemon/char_device.cc new file mode 100644 index 0000000..720c439 --- /dev/null +++ b/peripheralmanager/daemon/char_device.cc
@@ -0,0 +1,55 @@ +/* + * 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 "char_device.h" + +#include <fcntl.h> +#include <poll.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +namespace android { + +CharDevice::CharDevice() {} +CharDevice::~CharDevice() {} + +int CharDevice::Open(const char* pathname, int flags) { + return open(pathname, flags); +} + +int CharDevice::Close(int fd) { + return close(fd); +} + +int CharDevice::Ioctl(int fd, int request, void* argp) { + return ioctl(fd, request, argp); +} + +ssize_t CharDevice::Read(int fd, void* buf, size_t count) { + return read(fd, buf, count); +} + +ssize_t CharDevice::Write(int fd, const void* buf, size_t count) { + return write(fd, buf, count); +} + +int CharDevice::Poll(struct pollfd* fds, nfds_t nfds, int timeout) { + return poll(fds, nfds, timeout); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/char_device.h b/peripheralmanager/daemon/char_device.h new file mode 100644 index 0000000..53e6a3e --- /dev/null +++ b/peripheralmanager/daemon/char_device.h
@@ -0,0 +1,65 @@ +/* + * 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_CHAR_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_CHAR_DEVICE_H_ + +#include <poll.h> +#include <stdlib.h> + +#include <memory> + +namespace android { + +// Used to wrap the interface to a char device file. +// This can then be stubbed out and used in unittests. +class CharDeviceInterface { + public: + CharDeviceInterface(){}; + virtual ~CharDeviceInterface(){}; + + virtual int Open(const char* pathname, int flags) = 0; + virtual int Close(int fd) = 0; + virtual int Ioctl(int fd, int request, void* argp) = 0; + virtual ssize_t Read(int fd, void* buf, size_t count) = 0; + virtual ssize_t Write(int fd, const void* buf, size_t count) = 0; + virtual int Poll(struct pollfd* fds, nfds_t nfds, int timeout) = 0; +}; + +class CharDevice : public CharDeviceInterface { + public: + CharDevice(); + ~CharDevice() override; + + int Open(const char* pathname, int flags) override; + int Close(int fd) override; + int Ioctl(int fd, int request, void* argp) override; + ssize_t Read(int fd, void* buf, size_t count) override; + ssize_t Write(int fd, const void* buf, size_t count) override; + int Poll(struct pollfd* fds, nfds_t nfds, int timeout) override; +}; + +class CharDeviceFactory { + public: + CharDeviceFactory() {} + virtual ~CharDeviceFactory() {} + + virtual std::unique_ptr<CharDeviceInterface> NewCharDevice() = 0; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_CHAR_DEVICE_H_ \ No newline at end of file
diff --git a/peripheralmanager/daemon/fake_devices.cc b/peripheralmanager/daemon/fake_devices.cc new file mode 100644 index 0000000..2555a95 --- /dev/null +++ b/peripheralmanager/daemon/fake_devices.cc
@@ -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. + */ + +#include "fake_devices.h" + +#include <stdio.h> + +namespace android { + +FakeCharDevice::FakeCharDevice() {} +FakeCharDevice::~FakeCharDevice() {} + +// TODO(leecam): Implement these. +int FakeCharDevice::Open(const char* pathname, int flags) { + return 1; +} + +int FakeCharDevice::Close(int fd) { + return 0; +} + +int FakeCharDevice::Ioctl(int fd, int request, void* argp) { + return 0; +} + +ssize_t FakeCharDevice::Read(int fd, void* buf, size_t count) { + return count; +} + +ssize_t FakeCharDevice::Write(int fd, const void* buf, size_t count) { + return count; +} + +int FakeCharDevice::Poll(struct pollfd* fds, nfds_t nfds, int timeout) { + return 0; +} + +FakeDeviceFactory::FakeDeviceFactory() {} + +FakeDeviceFactory::~FakeDeviceFactory() {} + +std::unique_ptr<CharDeviceInterface> FakeDeviceFactory::NewCharDevice() { + return std::unique_ptr<CharDeviceInterface>(new FakeCharDevice()); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/fake_devices.h b/peripheralmanager/daemon/fake_devices.h new file mode 100644 index 0000000..d1aa7f9 --- /dev/null +++ b/peripheralmanager/daemon/fake_devices.h
@@ -0,0 +1,50 @@ +/* + * 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_FAKE_DEVICES_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_DEVICES_H_ + +#include <string> +#include <vector> + +#include "char_device.h" + +namespace android { + +class FakeCharDevice : public CharDeviceInterface { + public: + FakeCharDevice(); + ~FakeCharDevice() override; + + int Open(const char* pathname, int flags) override; + int Close(int fd) override; + int Ioctl(int fd, int request, void* argp) override; + ssize_t Read(int fd, void* buf, size_t count) override; + ssize_t Write(int fd, const void* buf, size_t count) override; + int Poll(struct pollfd* fds, nfds_t nfds, int timeout) override; +}; + +class FakeDeviceFactory : public CharDeviceFactory { + public: + FakeDeviceFactory(); + ~FakeDeviceFactory(); + + std::unique_ptr<CharDeviceInterface> NewCharDevice() override; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_DEVICES_H_
diff --git a/peripheralmanager/daemon/fake_i2c_devices.cc b/peripheralmanager/daemon/fake_i2c_devices.cc new file mode 100644 index 0000000..6cb7d8c --- /dev/null +++ b/peripheralmanager/daemon/fake_i2c_devices.cc
@@ -0,0 +1,103 @@ +/* + * 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 "fake_i2c_devices.h" + +#include <base/logging.h> +#include <linux/i2c-dev.h> +#include <linux/i2c.h> + +namespace android { + +FakeI2cDevice::FakeI2cDevice() {} +FakeI2cDevice::~FakeI2cDevice() {} + +int FakeI2cDevice::Open(const char* pathname, int flags) { + return 1; +} + +int FakeI2cDevice::Close(int fd) { + return 0; +} + +int FakeI2cDevice::Ioctl(int fd, int request, void* argp) { + if (request == I2C_SMBUS) { + struct i2c_smbus_ioctl_data* smbus_args = + reinterpret_cast<struct i2c_smbus_ioctl_data*>(argp); + + if (smbus_args->read_write == I2C_SMBUS_WRITE) { + uint8_t* data = smbus_args->data->block; + std::vector<uint8_t> temp; + if (smbus_args->size == I2C_SMBUS_I2C_BLOCK_DATA) { + temp.assign(data + 1, data + data[0] + 1); + } else if (smbus_args->size == I2C_SMBUS_WORD_DATA) { + temp.assign(data, data + 2); + } else if (smbus_args->size == I2C_SMBUS_BYTE_DATA) { + temp.assign(data, data + 1); + } + + registers_.emplace(smbus_args->command, temp); + LOG(INFO) << "writing " << temp.size() << " elements in " + << smbus_args->command; + return 0; + } else if (smbus_args->read_write == I2C_SMBUS_READ) { + if (!registers_.count(smbus_args->command)) { + LOG(INFO) << "no such register"; + return -1; + } + auto reg = registers_.find(smbus_args->command); + LOG(INFO) << "reading register " << smbus_args->command << " that has " + << reg->second.size() << " elements"; + + if (smbus_args->size == I2C_SMBUS_I2C_BLOCK_DATA) { + memcpy(smbus_args->data->block + 1, + reg->second.data(), + smbus_args->data->block[0]); + } else if (smbus_args->size == I2C_SMBUS_WORD_DATA) { + memcpy(smbus_args->data->block, reg->second.data(), 2); + } else if (smbus_args->size == I2C_SMBUS_BYTE_DATA) { + memcpy(smbus_args->data->block, reg->second.data(), 1); + } + return 0; + } + } else if (request == I2C_SLAVE) { + return 0; + } + + return -1; +} + +ssize_t FakeI2cDevice::Read(int fd, void* buf, size_t count) { + return count; +} + +ssize_t FakeI2cDevice::Write(int fd, const void* buf, size_t count) { + return count; +} + +int FakeI2cDevice::Poll(struct pollfd* fds, nfds_t nfds, int timeout) { + return 0; +} + +FakeI2cDeviceFactory::FakeI2cDeviceFactory() {} + +FakeI2cDeviceFactory::~FakeI2cDeviceFactory() {} + +std::unique_ptr<CharDeviceInterface> FakeI2cDeviceFactory::NewCharDevice() { + return std::unique_ptr<CharDeviceInterface>(new FakeI2cDevice()); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/fake_i2c_devices.h b/peripheralmanager/daemon/fake_i2c_devices.h new file mode 100644 index 0000000..6072cef --- /dev/null +++ b/peripheralmanager/daemon/fake_i2c_devices.h
@@ -0,0 +1,54 @@ +/* + * 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_FAKE_I2C_DEVICES_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_I2C_DEVICES_H_ + +#include <map> +#include <string> +#include <vector> + +#include "char_device.h" + +namespace android { + +class FakeI2cDevice : public CharDeviceInterface { + public: + FakeI2cDevice(); + ~FakeI2cDevice() override; + + int Open(const char* pathname, int flags) override; + int Close(int fd) override; + int Ioctl(int fd, int request, void* argp) override; + ssize_t Read(int fd, void* buf, size_t count) override; + ssize_t Write(int fd, const void* buf, size_t count) override; + int Poll(struct pollfd* fds, nfds_t nfds, int timeout) override; + + private: + std::map<uint8_t, std::vector<uint8_t>> registers_; +}; + +class FakeI2cDeviceFactory : public CharDeviceFactory { + public: + FakeI2cDeviceFactory(); + ~FakeI2cDeviceFactory(); + + std::unique_ptr<CharDeviceInterface> NewCharDevice() override; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_I2C_DEVICES_H_
diff --git a/peripheralmanager/daemon/gpio_driver.h b/peripheralmanager/daemon/gpio_driver.h new file mode 100644 index 0000000..084c0f3 --- /dev/null +++ b/peripheralmanager/daemon/gpio_driver.h
@@ -0,0 +1,78 @@ +/* + * 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_GPIO_DRIVER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include <android-base/unique_fd.h> +#include <base/macros.h> +#include <peripheralmanager/constants.h> + +namespace android { + +// This interface must be implemented by all +// Gpio drivers. +class GpioDriverInterface { + public: + GpioDriverInterface() {} + virtual ~GpioDriverInterface() {} + + // TODO(leecam): Init should have generic params. + virtual bool Init(uint32_t index) = 0; + + virtual bool SetValue(bool val) = 0; + virtual bool GetValue(bool* val) = 0; + virtual bool SetActiveType(GpioActiveType type) = 0; + virtual bool SetDirection(GpioDirection direction) = 0; + virtual bool SetEdgeType(GpioEdgeType type) = 0; + virtual bool GetPollingFd(::android::base::unique_fd* fd) = 0; +}; + +// The following is driver boilerplate. +// TODO(leecam): Abstract this into a seperate Driver class. +class GpioDriverInfoBase { + public: + GpioDriverInfoBase() {} + virtual ~GpioDriverInfoBase() {} + + virtual std::string Compat() = 0; + virtual std::unique_ptr<GpioDriverInterface> Probe() = 0; +}; + +template <class T, class PARAM> +class GpioDriverInfo : public GpioDriverInfoBase { + public: + explicit GpioDriverInfo(PARAM param) : param_(param) {} + ~GpioDriverInfo() override {} + + std::string Compat() override { return T::Compat(); } + + std::unique_ptr<GpioDriverInterface> Probe() override { + return std::unique_ptr<GpioDriverInterface>(new T(param_)); + } + + private: + PARAM param_; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_H_
diff --git a/peripheralmanager/daemon/gpio_driver_mock.h b/peripheralmanager/daemon/gpio_driver_mock.h new file mode 100644 index 0000000..f52b0f1 --- /dev/null +++ b/peripheralmanager/daemon/gpio_driver_mock.h
@@ -0,0 +1,58 @@ +/* + * 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_GPIO_DRIVER_MOCK_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_MOCK_H_ + +#include <stdint.h> + +#include <base/macros.h> +#include <gmock/gmock.h> + +#include "gpio_driver.h" + +namespace android { + +class GpioDriverMock : public GpioDriverInterface { + public: + explicit GpioDriverMock(void* arg) : is_input(true) {} + ~GpioDriverMock() {} + + static std::string Compat() { return "GPIOSYSFS"; } + + bool Init(uint32_t index) { return true; } + + bool SetValue(bool val) { return !is_input; }; + + bool GetValue(bool* val) { return true; }; + bool SetActiveType(GpioActiveType type) { return true; }; + + bool SetDirection(GpioDirection direction) { + is_input = direction == kDirectionIn; + return true; + }; + + bool SetEdgeType(GpioEdgeType type) { return true; }; + bool GetPollingFd(::android::base::unique_fd* fd) { return true; }; + + private: + bool is_input; + DISALLOW_COPY_AND_ASSIGN(GpioDriverMock); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_MOCK_H_
diff --git a/peripheralmanager/daemon/gpio_driver_sysfs.cc b/peripheralmanager/daemon/gpio_driver_sysfs.cc new file mode 100644 index 0000000..b49c2ff --- /dev/null +++ b/peripheralmanager/daemon/gpio_driver_sysfs.cc
@@ -0,0 +1,221 @@ +/* + * 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 "gpio_driver_sysfs.h" + +#include <fcntl.h> +#include <string> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <base/logging.h> + +namespace android { +namespace { + +// Path to sysfd gpio. +const char kSysfsGpioPathPrefix[] = "/sys/class/gpio/gpio"; + +// Path to export file. +const char kSysfsGpioExportPath[] = "/sys/class/gpio/export"; + +// Direction filename. +const char kDirection[] = "direction"; + +// Value filename. +const char kValue[] = "value"; + +// Active low filename. +const char kActiveLowFile[] = "active_low"; + +// Edge filename. +const char kEdge[] = "edge"; + +// Edge values. +const char kEdgeNoneValue[] = "none"; +const char kEdgeRisingValue[] = "rising"; +const char kEdgeFallingValue[] = "falling"; +const char kEdgeBothValue[] = "both"; + +// Direction values +const char kDirHigh[] = "high"; +const char kDirLow[] = "low"; +const char kDirIn[] = "in"; + +// Value values. +const char kValueHigh[] = "1"; +const char kValueLow[] = "0"; + +} // namespace + +GpioDriverSysfs::GpioDriverSysfs(void* arg) : fd_(-1) {} + +GpioDriverSysfs::~GpioDriverSysfs() { + if (fd_ >= 0) { + close(fd_); + } +} + +bool GpioDriverSysfs::Init(uint32_t index) { + if (!ExportGpio(index)) { + LOG(WARNING) << "GpioDriverSysfs: Failed to export " << index; + return false; + } + std::string path = kSysfsGpioPathPrefix + std::to_string(index); + + int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) { + PLOG(WARNING) << "Failed to open " << path; + return false; + } + + fd_ = fd; + return true; +} + +bool GpioDriverSysfs::SetValue(bool val) { + bool success = val ? Enable() : Disable(); + if (!success) { + LOG(WARNING) << "Failed to set the value of the GPIO. Is it configured as " + << "output?"; + } + return success; +} + +bool GpioDriverSysfs::GetValue(bool* val) { + std::string read_val; + if (!ReadFromFile(kValue, &read_val)) + return false; + if (read_val.size() < 1) { + return false; + } + // Remove any whitespace. + read_val = read_val[0]; + if (read_val == kValueHigh) + *val = true; + else + *val = false; + return true; +} + +bool GpioDriverSysfs::SetDirection(GpioDirection direction) { + switch (direction) { + case kDirectionIn: + return WriteToFile(kDirection, kDirIn); + case kDirectionOutInitiallyHigh: + return WriteToFile(kDirection, kDirHigh); + case kDirectionOutInitiallyLow: + return WriteToFile(kDirection, kDirLow); + } + return false; +} + +bool GpioDriverSysfs::SetActiveType(GpioActiveType type) { + if (type == kActiveLow) { + return WriteToFile(kActiveLowFile, kValueLow); + } else if (type == kActiveHigh) { + return WriteToFile(kActiveLowFile, kValueHigh); + } + return false; +} + +bool GpioDriverSysfs::SetEdgeType(GpioEdgeType type) { + switch (type) { + case kEdgeNone: + return WriteToFile(kEdge, kEdgeNoneValue); + case kEdgeRising: + return WriteToFile(kEdge, kEdgeRisingValue); + case kEdgeFalling: + return WriteToFile(kEdge, kEdgeFallingValue); + case kEdgeBoth: + return WriteToFile(kEdge, kEdgeBothValue); + } + return false; +} + +bool GpioDriverSysfs::GetPollingFd(::android::base::unique_fd* fd) { + int f = openat(fd_, kValue, O_RDWR); + if (f < 0) + return false; + + fd->reset(f); + return true; +} + +bool GpioDriverSysfs::Enable() { + return WriteToFile(kValue, kValueHigh); +} + +bool GpioDriverSysfs::Disable() { + return WriteToFile(kValue, kValueLow); +} + +bool GpioDriverSysfs::WriteToFile(const std::string& file, + const std::string& value) { + int fd = openat(fd_, file.c_str(), O_RDWR); + if (fd < 0) + return false; + + ssize_t bytes = write(fd, value.c_str(), value.size()); + close(fd); + if (bytes < 0) + return false; + if ((size_t)bytes != value.size()) + return false; + return true; +} + +bool GpioDriverSysfs::ReadFromFile(const std::string& file, + std::string* value) { + int fd = openat(fd_, file.c_str(), O_RDONLY); + if (fd < 0) + return false; + char tmp_buf[16] = ""; + ssize_t bytes = read(fd, tmp_buf, sizeof(tmp_buf)); + close(fd); + if (bytes < 0) + return false; + value->assign(tmp_buf, bytes); + return true; +} + +bool GpioDriverSysfs::ExportGpio(uint32_t index) { + // Check if the pin is already exported. + // It will fail otherwise. + std::string path = kSysfsGpioPathPrefix + std::to_string(index); + struct stat stat_buf; + if (!stat(path.c_str(), &stat_buf)) + return true; + + int fd = open(kSysfsGpioExportPath, O_WRONLY); + if (fd < 0) { + PLOG(WARNING) << "Failed to open " << kSysfsGpioExportPath; + return false; + } + std::string value = std::to_string(index); + ssize_t bytes = write(fd, value.c_str(), value.size()); + close(fd); + if (bytes < 0) { + PLOG(WARNING) << "Failed to write " << bytes; + return false; + } + if ((size_t)bytes != value.size()) + return false; + return true; +} + +} // namespace android
diff --git a/peripheralmanager/daemon/gpio_driver_sysfs.h b/peripheralmanager/daemon/gpio_driver_sysfs.h new file mode 100644 index 0000000..690066a --- /dev/null +++ b/peripheralmanager/daemon/gpio_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_GPIO_DRIVER_SYSFS_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_SYSFS_H_ + +#include <stdint.h> + +#include <base/macros.h> + +#include "gpio_driver.h" + +namespace android { + +class GpioDriverSysfs : public GpioDriverInterface { + public: + explicit GpioDriverSysfs(void* arg); + ~GpioDriverSysfs(); + + static std::string Compat() { return "GPIOSYSFS"; } + + bool Init(uint32_t index) override; + + // Gpio Driver interface. + bool SetValue(bool val) override; + bool GetValue(bool* val) override; + bool SetActiveType(GpioActiveType type) override; + bool SetDirection(GpioDirection direction) override; + bool SetEdgeType(GpioEdgeType type) override; + bool GetPollingFd(::android::base::unique_fd* fd) override; + + private: + bool Enable(); + bool Disable(); + bool ExportGpio(uint32_t index); + bool WriteToFile(const std::string& file, const std::string& value); + bool ReadFromFile(const std::string& file, std::string* value); + + int fd_; + + DISALLOW_COPY_AND_ASSIGN(GpioDriverSysfs); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_DRIVER_SYSFS_H_
diff --git a/peripheralmanager/daemon/gpio_manager.cc b/peripheralmanager/daemon/gpio_manager.cc new file mode 100644 index 0000000..1a47941 --- /dev/null +++ b/peripheralmanager/daemon/gpio_manager.cc
@@ -0,0 +1,114 @@ +/* + * 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 "gpio_manager.h" + +#include <base/logging.h> + +namespace android { + +std::unique_ptr<GpioManager> g_gpio_manager; + +GpioManager::GpioManager() {} + +GpioManager::~GpioManager() {} + +// static +GpioManager* GpioManager::GetGpioManager() { + if (!g_gpio_manager) { + g_gpio_manager.reset(new GpioManager()); + } + return g_gpio_manager.get(); +} + +void GpioManager::ResetGpioManager() { + g_gpio_manager.reset(); +} + +bool GpioManager::RegisterGpioSysfs(const std::string& name, uint32_t index) { + if (sysfs_pins_.count(name)) + return false; + sysfs_pins_[name].index = index; + return true; +} + +bool GpioManager::SetPinMux(const std::string& name, const std::string& mux) { + if (!sysfs_pins_.count(name)) + return false; + sysfs_pins_[name].mux = mux; + return true; +} + +std::vector<std::string> GpioManager::GetGpioPins() { + std::vector<std::string> pins; + for (auto& i : sysfs_pins_) + pins.push_back(i.first); + return pins; +} + +bool GpioManager::HasGpio(const std::string& pin_name) { + return sysfs_pins_.count(pin_name); +} + +bool GpioManager::RegisterDriver( + std::unique_ptr<GpioDriverInfoBase> driver_info) { + std::string key = driver_info->Compat(); + driver_infos_[key] = std::move(driver_info); + return true; +} + +std::unique_ptr<GpioPin> GpioManager::OpenGpioPin(const std::string& name) { + // Get the Pin from the BSP. + auto pin_it = sysfs_pins_.find(name); + if (pin_it == sysfs_pins_.end()) { + LOG(WARNING) << "GpioManager: Pin not found. " << name; + return nullptr; + } + + // Check its not alread in use + if (pin_it->second.driver_) { + LOG(WARNING) << "GpioManager: Pin in use. " << name; + return nullptr; + } + + // Find a driver. + // Currently there is only hardcoded support for GPIOSYSFS + auto driver_info_it = driver_infos_.find("GPIOSYSFS"); + + // Fail if there is no driver. + if (driver_info_it == driver_infos_.end()) { + LOG(WARNING) << "GpioManager: Failed to find driver " << name; + return nullptr; + } + + std::unique_ptr<GpioDriverInterface> driver(driver_info_it->second->Probe()); + + // Set pin mux + if (!pin_it->second.mux.empty()) { + PinMuxManager::GetPinMuxManager()->SetGpio(pin_it->second.mux); + } + + if (!driver->Init(pin_it->second.index)) { + LOG(WARNING) << "GpioManager: Failed to init driver " << name; + return nullptr; + } + + pin_it->second.driver_ = std::move(driver); + + return std::unique_ptr<GpioPin>(new GpioPin(&(pin_it->second))); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/gpio_manager.h b/peripheralmanager/daemon/gpio_manager.h new file mode 100644 index 0000000..52bd779 --- /dev/null +++ b/peripheralmanager/daemon/gpio_manager.h
@@ -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. + */ + +#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include "gpio_driver.h" +#include "pin_mux_manager.h" + +namespace android { + +struct GpioPinSysfs { + uint32_t index; + std::string mux; + std::unique_ptr<GpioDriverInterface> driver_; +}; + +class GpioPin { + public: + // TODO(leecam): pins should have a generic device + // reference, not a sysfs one. + explicit GpioPin(GpioPinSysfs* pin) : pin_(pin) {} + ~GpioPin() { + if (!pin_->mux.empty()) { + PinMuxManager::GetPinMuxManager()->ReleaseGpio(pin_->mux); + } + pin_->driver_.reset(); + } + + bool SetValue(bool val) { return pin_->driver_->SetValue(val); } + + bool GetValue(bool* val) { return pin_->driver_->GetValue(val); } + + bool SetDirection(GpioDirection direction) { + if (!pin_->mux.empty()) { + bool dir = true; + if (direction == kDirectionIn) + dir = false; + if (!PinMuxManager::GetPinMuxManager()->SetGpioDirection(pin_->mux, + dir)) { + return false; + } + } + return pin_->driver_->SetDirection(direction); + } + + bool SetActiveType(GpioActiveType type) { + return pin_->driver_->SetActiveType(type); + } + + bool SetEdgeType(GpioEdgeType type) { + return pin_->driver_->SetEdgeType(type); + } + + bool GetPollingFd(::android::base::unique_fd* fd) { + return pin_->driver_->GetPollingFd(fd); + } + + private: + GpioPinSysfs* pin_; +}; + +class GpioManager { + public: + friend class GpioManagerTest; + ~GpioManager(); + + // Get the singleton. + static GpioManager* GetGpioManager(); + + // Delete the GpioManager (used for test); + static void ResetGpioManager(); + + // Used by the BSP to tell PMan of an GPIO Pin. + bool RegisterGpioSysfs(const std::string& name, uint32_t index); + bool SetPinMux(const std::string& name, const std::string& mux); + + // Query for available pins. + std::vector<std::string> GetGpioPins(); + bool HasGpio(const std::string& pin_name); + + bool RegisterDriver(std::unique_ptr<GpioDriverInfoBase> driver_info); + + std::unique_ptr<GpioPin> OpenGpioPin(const std::string& name); + + private: + GpioManager(); + + std::map<std::string, std::unique_ptr<GpioDriverInfoBase>> driver_infos_; + std::map<std::string, GpioPinSysfs> sysfs_pins_; + + DISALLOW_COPY_AND_ASSIGN(GpioManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_GPIO_MANAGER_H_
diff --git a/peripheralmanager/daemon/gpio_manager_unittest.cc b/peripheralmanager/daemon/gpio_manager_unittest.cc new file mode 100644 index 0000000..0e7b07b --- /dev/null +++ b/peripheralmanager/daemon/gpio_manager_unittest.cc
@@ -0,0 +1,52 @@ +/* + * 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 <stdio.h> + +#include <gtest/gtest.h> + +#include "gpio_driver_sysfs.h" +#include "gpio_manager.h" + +namespace android { + +class GpioManagerTest : public ::testing::Test { + public: + GpioManagerTest() {} + ~GpioManagerTest() = default; + + protected: + GpioManager manager; +}; + +TEST_F(GpioManagerTest, RegisterDriver) { + manager.RegisterDriver(std::unique_ptr<GpioDriverInfoBase>( + new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr))); +} + +TEST_F(GpioManagerTest, BasicOpen) { + manager.RegisterDriver(std::unique_ptr<GpioDriverInfoBase>( + new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr))); + + manager.RegisterGpioSysfs("IO11", 40); + + std::unique_ptr<GpioPin> pin(manager.OpenGpioPin("IO11")); +} + +// TODO(leecam): Once this stablizes and has a stub, +// write lots more tests. + +} // namespace android \ No newline at end of file
diff --git a/peripheralmanager/daemon/i2c_driver.h b/peripheralmanager/daemon/i2c_driver.h new file mode 100644 index 0000000..7eac065 --- /dev/null +++ b/peripheralmanager/daemon/i2c_driver.h
@@ -0,0 +1,86 @@ +/* + * 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_I2C_DRIVER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" + +namespace android { + +class I2cDriverInterface { + public: + I2cDriverInterface() {} + virtual ~I2cDriverInterface() {} + + // TODO(leecam): Init should have generic params. + virtual bool Init(uint32_t bus_id, uint32_t address) = 0; + + // Returns 0 on success, errno on errors. + virtual int32_t Read(void* data, uint32_t size, uint32_t* bytes_read) = 0; + virtual int32_t ReadRegByte(uint8_t reg, uint8_t* val) = 0; + virtual int32_t ReadRegWord(uint8_t reg, uint16_t* val) = 0; + virtual int32_t ReadRegBuffer(uint8_t reg, + uint8_t* data, + uint32_t size, + uint32_t* bytes_read) = 0; + + virtual int32_t Write(const void* data, + uint32_t size, + uint32_t* bytes_written) = 0; + virtual int32_t WriteRegByte(uint8_t reg, uint8_t val) = 0; + virtual int32_t WriteRegWord(uint8_t reg, uint16_t val) = 0; + virtual int32_t WriteRegBuffer(uint8_t reg, + const uint8_t* data, + uint32_t size, + uint32_t* bytes_written) = 0; +}; + +class I2cDriverInfoBase { + public: + I2cDriverInfoBase() {} + virtual ~I2cDriverInfoBase() {} + + virtual std::string Compat() = 0; + virtual std::unique_ptr<I2cDriverInterface> Probe() = 0; +}; + +template <class T, class PARAM> +class I2cDriverInfo : public I2cDriverInfoBase { + public: + explicit I2cDriverInfo(PARAM param) : param_(param) {} + ~I2cDriverInfo() override {} + + std::string Compat() override { return T::Compat(); } + + std::unique_ptr<I2cDriverInterface> Probe() override { + return std::unique_ptr<I2cDriverInterface>(new T(param_)); + } + + private: + PARAM param_; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_H_
diff --git a/peripheralmanager/daemon/i2c_driver_i2cdev.cc b/peripheralmanager/daemon/i2c_driver_i2cdev.cc new file mode 100644 index 0000000..b4f2280 --- /dev/null +++ b/peripheralmanager/daemon/i2c_driver_i2cdev.cc
@@ -0,0 +1,207 @@ +/* + * 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 "i2c_driver_i2cdev.h" + +#include <fcntl.h> +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#include <sys/ioctl.h> +#include <string> + +#include <base/logging.h> + +namespace android { +namespace { + +const char kI2cDevPath[] = "/dev/i2c-"; + +} // namespace + +I2cDriverI2cDev::I2cDriverI2cDev(CharDeviceFactory* char_device_factory) + : fd_(-1), char_device_factory_(char_device_factory) {} + +I2cDriverI2cDev::~I2cDriverI2cDev() { + if (fd_ >= 0 && char_interface_ != nullptr) { + char_interface_->Close(fd_); + } +} + +bool I2cDriverI2cDev::Init(uint32_t bus_id, uint32_t address) { + if (fd_ >= 0) { + return false; + } + // 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(); + } + + std::string path = kI2cDevPath + std::to_string(bus_id); + + int fd = char_interface_->Open(path.c_str(), O_RDWR); + if (fd < 0) + return false; + uintptr_t tmp_addr = address; + if (char_interface_->Ioctl(fd, I2C_SLAVE, (void*)tmp_addr) < 0) { + LOG(ERROR) << "Failed to set I2C slave"; + char_interface_->Close(fd); + return false; + } + + fd_ = fd; + + return true; +} + +int32_t I2cDriverI2cDev::Read(void* data, uint32_t size, uint32_t* bytes_read) { + *bytes_read = char_interface_->Read(fd_, data, size); + return *bytes_read == size ? 0 : EIO; +} + +int32_t I2cDriverI2cDev::ReadRegByte(uint8_t reg, uint8_t* val) { + union i2c_smbus_data read_data; + struct i2c_smbus_ioctl_data smbus_args { + .command = reg, .read_write = I2C_SMBUS_READ, .size = I2C_SMBUS_BYTE_DATA, + .data = &read_data, + }; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(INFO) << "Failed I2C_SMBUS"; + return EIO; + } + + *val = read_data.byte; + return 0; +} + +int32_t I2cDriverI2cDev::ReadRegWord(uint8_t reg, uint16_t* val) { + union i2c_smbus_data read_data; + struct i2c_smbus_ioctl_data smbus_args { + .command = reg, .read_write = I2C_SMBUS_READ, .size = I2C_SMBUS_WORD_DATA, + .data = &read_data, + }; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(INFO) << "Failed I2C_SMBUS"; + return EIO; + } + + *val = read_data.word; + return 0; +} + +int32_t I2cDriverI2cDev::ReadRegBuffer(uint8_t reg, + uint8_t* data, + uint32_t size, + uint32_t* bytes_read) { + *bytes_read = 0; + if (size > I2C_SMBUS_BLOCK_MAX) { + LOG(WARNING) << "Can't read more than 32 bytes at a time."; + return EINVAL; + } + + union i2c_smbus_data read_data; + read_data.block[0] = size; + + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_READ; + smbus_args.size = I2C_SMBUS_I2C_BLOCK_DATA; + smbus_args.data = &read_data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(ERROR) << "Failed I2C_SMBUS"; + return EIO; + } + + memcpy(data, &read_data.block[1], size); + *bytes_read = size; + + return 0; +} + +int32_t I2cDriverI2cDev::Write(const void* data, + uint32_t size, + uint32_t* bytes_written) { + *bytes_written = char_interface_->Write(fd_, data, size); + return *bytes_written == size ? 0 : EIO; +} + +int32_t I2cDriverI2cDev::WriteRegByte(uint8_t reg, uint8_t val) { + union i2c_smbus_data write_data; + write_data.byte = val; + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_WRITE; + smbus_args.size = I2C_SMBUS_BYTE_DATA; + smbus_args.data = &write_data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + return EIO; + } + return 0; +} + +int32_t I2cDriverI2cDev::WriteRegWord(uint8_t reg, uint16_t val) { + union i2c_smbus_data write_data; + write_data.word = val; + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_WRITE; + smbus_args.size = I2C_SMBUS_WORD_DATA; + smbus_args.data = &write_data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + return EIO; + } + return 0; +} + +int32_t I2cDriverI2cDev::WriteRegBuffer(uint8_t reg, + const uint8_t* data, + uint32_t size, + uint32_t* bytes_written) { + *bytes_written = 0; + if (size > I2C_SMBUS_BLOCK_MAX) { + LOG(WARNING) << "Can't write more than 32 bytes at a time."; + return EINVAL; + } + + union i2c_smbus_data write_data; + write_data.block[0] = size; + memcpy(&write_data.block[1], data, size); + + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_WRITE; + smbus_args.size = I2C_SMBUS_I2C_BLOCK_DATA; + smbus_args.data = &write_data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(ERROR) << "Failed I2C_SMBUS"; + return EIO; + } + + *bytes_written = size; + + return 0; +} + +} // namespace
diff --git a/peripheralmanager/daemon/i2c_driver_i2cdev.h b/peripheralmanager/daemon/i2c_driver_i2cdev.h new file mode 100644 index 0000000..8282b47 --- /dev/null +++ b/peripheralmanager/daemon/i2c_driver_i2cdev.h
@@ -0,0 +1,70 @@ +/* + * 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_I2C_DRIVER_I2CDEV_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_I2CDEV_H_ + +#include <stdint.h> + +#include <memory> + +#include <base/macros.h> + +#include "char_device.h" +#include "i2c_driver.h" + +namespace android { + +class I2cDriverI2cDev : public I2cDriverInterface { + public: + explicit I2cDriverI2cDev(CharDeviceFactory* char_device_factory); + ~I2cDriverI2cDev(); + + static std::string Compat() { return "I2CDEV"; } + + bool Init(uint32_t bus_id, uint32_t address) override; + + int32_t Read(void* data, uint32_t size, uint32_t* bytes_read) override; + int32_t ReadRegByte(uint8_t reg, uint8_t* val) override; + int32_t ReadRegWord(uint8_t reg, uint16_t* val) override; + int32_t ReadRegBuffer(uint8_t reg, + uint8_t* data, + uint32_t size, + uint32_t* bytes_read) override; + + int32_t Write(const void* data, + uint32_t size, + uint32_t* bytes_written) override; + int32_t WriteRegByte(uint8_t reg, uint8_t val) override; + int32_t WriteRegWord(uint8_t reg, uint16_t val) override; + int32_t WriteRegBuffer(uint8_t reg, + const uint8_t* data, + uint32_t size, + uint32_t* bytes_written) override; + + private: + int fd_; + + // Used for unit testing and is null in production. + // Ownership is in the test and outlives this class. + CharDeviceFactory* char_device_factory_; + std::unique_ptr<CharDeviceInterface> char_interface_; + DISALLOW_COPY_AND_ASSIGN(I2cDriverI2cDev); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_I2CDEV_H_
diff --git a/peripheralmanager/daemon/i2c_manager.cc b/peripheralmanager/daemon/i2c_manager.cc new file mode 100644 index 0000000..7ca084e --- /dev/null +++ b/peripheralmanager/daemon/i2c_manager.cc
@@ -0,0 +1,126 @@ +/* + * 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 "i2c_manager.h" + +#include <base/logging.h> + +#include "pin_mux_manager.h" + +namespace android { + +std::unique_ptr<I2cManager> g_i2c_manager; + +I2cManager::I2cManager() {} + +I2cManager::~I2cManager() {} + +// static +I2cManager* I2cManager::GetI2cManager() { + if (!g_i2c_manager) { + g_i2c_manager.reset(new I2cManager()); + } + return g_i2c_manager.get(); +} + +// static +void I2cManager::ResetI2cManager() { + g_i2c_manager.reset(); +} + +bool I2cManager::RegisterI2cDevBus(const std::string& name, + uint32_t bus) { + if (i2cdev_buses_.count(name)) + return false; + i2cdev_buses_.emplace(name, I2cDevBus(bus)); + return true; +} + +std::vector<std::string> I2cManager::GetI2cDevBuses() { + std::vector<std::string> buses; + for (auto& i : i2cdev_buses_) + buses.push_back(i.first); + return buses; +} + +bool I2cManager::HasI2cDevBus(const std::string& name) { + return i2cdev_buses_.count(name); +} + +bool I2cManager::RegisterDriver( + std::unique_ptr<I2cDriverInfoBase> driver_info) { + std::string key = driver_info->Compat(); + driver_infos_[key] = std::move(driver_info); + return true; +} + +bool I2cManager::SetPinMux(const std::string& name, const std::string& mux) { + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = mux; + return true; +} + +bool I2cManager::SetPinMuxWithGroup(const std::string& name, + const std::string& mux, + const std::string& group) { + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = group; + return true; +} + +std::unique_ptr<I2cDevice> I2cManager::OpenI2cDevice(const std::string& name, uint32_t address) { + LOG(INFO) << "OpenI2cDevice " << name << " " << address; + // Get the Bus from the BSP. + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return nullptr; + + // Check its not already in use + if (bus_it->second.driver_.count(address)) { + return nullptr; + } + + // Find a driver. + // Currently there is only hardcoded support for I2CDEV + auto driver_info_it = driver_infos_.find("I2CDEV"); + + // Fail if there is no driver. + if (driver_info_it == driver_infos_.end()) + return nullptr; + + std::unique_ptr<I2cDriverInterface> driver(driver_info_it->second->Probe()); + + if (!driver->Init(bus_it->second.bus, address)) + return nullptr; + + // Set Pin muxing. + if (!bus_it->second.mux.empty()) { + PinMuxManager::GetPinMuxManager()->SetSource(bus_it->second.mux, + bus_it->second.mux_group); + } + + bus_it->second.driver_[address] = std::move(driver); + + return std::unique_ptr<I2cDevice>(new I2cDevice(&(bus_it->second), address)); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/i2c_manager.h b/peripheralmanager/daemon/i2c_manager.h new file mode 100644 index 0000000..5627b4d --- /dev/null +++ b/peripheralmanager/daemon/i2c_manager.h
@@ -0,0 +1,135 @@ +/* + * 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_I2C_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" +#include "pin_mux_manager.h" +#include "i2c_driver.h" + +namespace android { + +struct I2cDevBus { + explicit I2cDevBus(uint32_t b) : bus(b) {} + uint32_t bus; + std::string mux; + std::string mux_group; + std::map<uint32_t, std::unique_ptr<I2cDriverInterface>> driver_; +}; + +class I2cDevice { + public: + I2cDevice(I2cDevBus* bus, uint32_t address) : bus_(bus), address_(address) {} + ~I2cDevice() { + if (!bus_->mux.empty()) { + PinMuxManager::GetPinMuxManager()->ReleaseSource(bus_->mux, + bus_->mux_group); + } + bus_->driver_.erase(address_); + } + + int32_t Read(void* data, uint32_t size, uint32_t* bytes_read) { + return bus_->driver_[address_]->Read(data, size, bytes_read); + } + + int32_t ReadRegByte(uint8_t reg, uint8_t* val) { + return bus_->driver_[address_]->ReadRegByte(reg, val); + } + + int32_t ReadRegWord(uint8_t reg, uint16_t* val) { + return bus_->driver_[address_]->ReadRegWord(reg, val); + } + + int32_t ReadRegBuffer(uint8_t reg, + uint8_t* data, + uint32_t size, + uint32_t* bytes_read) { + return bus_->driver_[address_]->ReadRegBuffer(reg, data, size, bytes_read); + } + + int32_t Write(const void* data, uint32_t size, uint32_t* bytes_written) { + return bus_->driver_[address_]->Write(data, size, bytes_written); + } + + int32_t WriteRegByte(uint8_t reg, uint8_t val) { + return bus_->driver_[address_]->WriteRegByte(reg, val); + } + + int32_t WriteRegWord(uint8_t reg, uint16_t val) { + return bus_->driver_[address_]->WriteRegWord(reg, val); + } + + int32_t WriteRegBuffer(uint8_t reg, + const uint8_t* data, + uint32_t size, + uint32_t* bytes_written) { + return bus_->driver_[address_]->WriteRegBuffer( + reg, data, size, bytes_written); + } + + private: + I2cDevBus* bus_; + uint32_t address_; +}; + +class I2cManager { + public: + friend class I2cManagerTest; + ~I2cManager(); + + // Get the singleton. + static I2cManager* GetI2cManager(); + + // Resets the global I2c manager (used for testing). + static void ResetI2cManager(); + + bool RegisterI2cDevBus(const std::string& name, uint32_t bus); + + std::vector<std::string> GetI2cDevBuses(); + bool HasI2cDevBus(const std::string& name); + + bool SetPinMux(const std::string& name, const std::string& mux); + bool SetPinMuxWithGroup(const std::string& name, + const std::string& mux, + const std::string& group); + + bool RegisterDriver(std::unique_ptr<I2cDriverInfoBase> driver_info); + + std::unique_ptr<I2cDevice> OpenI2cDevice(const std::string& name, + uint32_t address); + + private: + I2cManager(); + + std::map<std::string, std::unique_ptr<I2cDriverInfoBase>> driver_infos_; + std::map<std::string, I2cDevBus> i2cdev_buses_; + + DISALLOW_COPY_AND_ASSIGN(I2cManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_MANAGER_H_
diff --git a/peripheralmanager/daemon/led_driver.h b/peripheralmanager/daemon/led_driver.h new file mode 100644 index 0000000..15c25e6 --- /dev/null +++ b/peripheralmanager/daemon/led_driver.h
@@ -0,0 +1,71 @@ +/* + * 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_LED_DRIVER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_LED_DRIVER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include <base/macros.h> + +namespace android { + +class LedDriverInterface { + public: + LedDriverInterface() {} + virtual ~LedDriverInterface() {} + + // TODO(leecam): Init should have generic params. + virtual bool Init(const std::string& name) = 0; + + virtual bool SetBrightness(uint32_t val) = 0; + + virtual bool GetBrightness(uint32_t* val) = 0; + + virtual bool GetMaxBrightness(uint32_t* val) = 0; +}; + +class LedDriverInfoBase { + public: + LedDriverInfoBase() {} + virtual ~LedDriverInfoBase() {} + + virtual std::string Compat() = 0; + virtual std::unique_ptr<LedDriverInterface> Probe() = 0; +}; + +template <class T, class PARAM> +class LedDriverInfo : public LedDriverInfoBase { + public: + explicit LedDriverInfo(PARAM param) : param_(param) {} + ~LedDriverInfo() override {} + + std::string Compat() override { return T::Compat(); } + + std::unique_ptr<LedDriverInterface> Probe() override { + return std::unique_ptr<LedDriverInterface>(new T(param_)); + } + + private: + PARAM param_; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_LED_DRIVER_H_
diff --git a/peripheralmanager/daemon/led_driver_sysfs.cc b/peripheralmanager/daemon/led_driver_sysfs.cc new file mode 100644 index 0000000..0292082 --- /dev/null +++ b/peripheralmanager/daemon/led_driver_sysfs.cc
@@ -0,0 +1,109 @@ +/* + * 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 "led_driver_sysfs.h" + +#include <fcntl.h> +#include <string> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <base/logging.h> + +namespace android { +namespace { + +const char kSysfsLedPathPrefix[] = "/sys/class/leds/"; +const char kMaxBrightnessFilename[] = "max_brightness"; +const char kBrightnessFilename[] = "brightness"; + +} // namespace + +LedDriverSysfs::LedDriverSysfs(std::string* prefix) + : fd_(-1), prefix_(prefix) {} + +LedDriverSysfs::~LedDriverSysfs() { + if (fd_ >= 0) { + close(fd_); + } +} + +bool LedDriverSysfs::Init(const std::string& name) { + LOG(INFO) << "Opening " << name; + + // If a custom prefix was defined, use it. + std::string path = prefix_ ? *prefix_ + name : kSysfsLedPathPrefix + name; + + int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) { + PLOG(WARNING) << "Failed to open " << path; + return false; + } + + fd_ = fd; + return true; +} + +bool LedDriverSysfs::SetBrightness(uint32_t val) { + return WriteToFile(kBrightnessFilename, std::to_string(val)); +} + +bool LedDriverSysfs::GetBrightness(uint32_t* val) { + std::string str_val; + if (!ReadFromFile(kBrightnessFilename, &str_val)) + return false; + *val = std::stoi(str_val); + return true; +} + +bool LedDriverSysfs::GetMaxBrightness(uint32_t* val) { + std::string str_val; + if (!ReadFromFile(kMaxBrightnessFilename, &str_val)) + return false; + *val = std::stoi(str_val); + return true; +} + +bool LedDriverSysfs::ReadFromFile(const std::string& file, std::string* value) { + int fd = openat(fd_, file.c_str(), O_RDONLY); + if (fd < 0) + return false; + char tmp_buf[16] = ""; + ssize_t bytes = read(fd, tmp_buf, sizeof(tmp_buf)); + close(fd); + if (bytes < 0) + return false; + value->assign(tmp_buf, bytes); + return true; +} + +bool LedDriverSysfs::WriteToFile(const std::string& file, + const std::string& value) { + int fd = openat(fd_, file.c_str(), O_RDWR); + if (fd < 0) + return false; + + ssize_t bytes = write(fd, value.c_str(), value.size()); + close(fd); + if (bytes < 0) + return false; + if ((size_t)bytes != value.size()) + return false; + return true; +} + +} // namespace android
diff --git a/peripheralmanager/daemon/led_driver_sysfs.h b/peripheralmanager/daemon/led_driver_sysfs.h new file mode 100644 index 0000000..c4c46fc --- /dev/null +++ b/peripheralmanager/daemon/led_driver_sysfs.h
@@ -0,0 +1,55 @@ +/* + * 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_LED_DRIVER_SYSFS_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_LED_DRIVER_SYSFS_H_ + +#include <stdint.h> + +#include <base/macros.h> + +#include "led_driver.h" + +namespace android { + +class LedDriverSysfs : public LedDriverInterface { + public: + explicit LedDriverSysfs(std::string* prefix); + ~LedDriverSysfs(); + + static std::string Compat() { return "LEDSYSFS"; } + + bool Init(const std::string& name) override; + bool SetBrightness(uint32_t val) override; + bool GetBrightness(uint32_t* val) override; + bool GetMaxBrightness(uint32_t* val) override; + + private: + bool ReadFromFile(const std::string& file, std::string* value); + bool WriteToFile(const std::string& file, const std::string& value); + + int fd_; + + // Used for unit test only. + // Ownership is in the test. + std::string* prefix_; + + DISALLOW_COPY_AND_ASSIGN(LedDriverSysfs); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_LED_DRIVER_SYSFS_H_
diff --git a/peripheralmanager/daemon/led_manager.cc b/peripheralmanager/daemon/led_manager.cc new file mode 100644 index 0000000..72e200f --- /dev/null +++ b/peripheralmanager/daemon/led_manager.cc
@@ -0,0 +1,107 @@ +/* + * 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 "led_manager.h" + +#include <base/logging.h> + +namespace android { + +std::unique_ptr<LedManager> g_led_manager; + +LedManager::LedManager() {} + +LedManager::~LedManager() {} + +// static +LedManager* LedManager::GetLedManager() { + if (!g_led_manager) { + g_led_manager.reset(new LedManager()); + } + return g_led_manager.get(); +} + +// static +void LedManager::ResetLedManager() { + g_led_manager.reset(); +} + +bool LedManager::RegisterDriver( + std::unique_ptr<LedDriverInfoBase> driver_info) { + std::string key = driver_info->Compat(); + driver_infos_[key] = std::move(driver_info); + return true; +} + +bool LedManager::RegisterLedSysfs(const std::string& name, + const std::string& led_name) { + if (leds_.count(name)) + return false; + leds_[name].name = led_name; + return true; +} + +std::unique_ptr<Led> LedManager::OpenLed(const std::string& name) { + auto led_it = leds_.find(name); + if (led_it == leds_.end()) { + LOG(WARNING) << "LedManager: Led not found. " << name; + return nullptr; + } + + // Check its not alread in use + if (led_it->second.driver_) { + LOG(WARNING) << "LedManager: Led in use. " << name; + return nullptr; + } + + // Find a driver. + auto driver_info_it = driver_infos_.find("LEDSYSFS"); + + // Fail if there is no driver. + if (driver_info_it == driver_infos_.end()) { + LOG(WARNING) << "LedManager: Failed to find driver " << name; + return nullptr; + } + + std::unique_ptr<LedDriverInterface> driver(driver_info_it->second->Probe()); + + // Set pin mux + if (!led_it->second.mux.empty()) { + // TODO(leecam): Enable pin muxing + } + + if (!driver->Init(led_it->second.name)) { + LOG(WARNING) << "LedManager: Failed to init driver " << name; + return nullptr; + } + + led_it->second.driver_ = std::move(driver); + + return std::unique_ptr<Led>(new Led(&(led_it->second))); +} + +std::vector<std::string> LedManager::GetLeds() { + std::vector<std::string> leds; + for (auto& i : leds_) + leds.push_back(i.first); + return leds; +} + +bool LedManager::HasLed(const std::string& name) { + return leds_.count(name); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/led_manager.h b/peripheralmanager/daemon/led_manager.h new file mode 100644 index 0000000..b6c93f9 --- /dev/null +++ b/peripheralmanager/daemon/led_manager.h
@@ -0,0 +1,95 @@ +/* + * 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_LED_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_LED_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include "led_driver.h" +#include "pin_mux_manager.h" + +namespace android { + +struct LedSysfs { + std::string name; + std::string mux; + std::unique_ptr<LedDriverInterface> driver_; +}; + +class Led { + public: + explicit Led(LedSysfs* led) : led_(led) {} + ~Led() { + if (!led_->mux.empty()) { + // TODO(leecam): Set up pin muxing + } + led_->driver_.reset(); + } + + bool SetBrightness(uint32_t val) { return led_->driver_->SetBrightness(val); } + + bool GetBrightness(uint32_t* val) { + return led_->driver_->GetBrightness(val); + } + + bool GetMaxBrightness(uint32_t* val) { + return led_->driver_->GetMaxBrightness(val); + } + + private: + LedSysfs* led_; +}; + +class LedManager { + public: + friend class LedManagerTest; + ~LedManager(); + + // Get the singleton. + static LedManager* GetLedManager(); + static void ResetLedManager(); + + // Used by the BSP to tell PMan of an sysfs led. + bool RegisterLedSysfs(const std::string& name, const std::string& led_name); + bool SetPinMux(const std::string& name, const std::string& mux); + + std::vector<std::string> GetLeds(); + bool HasLed(const std::string& name); + + bool RegisterDriver(std::unique_ptr<LedDriverInfoBase> driver_info); + + std::unique_ptr<Led> OpenLed(const std::string& name); + + private: + LedManager(); + + std::map<std::string, std::unique_ptr<LedDriverInfoBase>> driver_infos_; + std::map<std::string, LedSysfs> leds_; + + DISALLOW_COPY_AND_ASSIGN(LedManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_LED_MANAGER_H_
diff --git a/peripheralmanager/daemon/main.cc b/peripheralmanager/daemon/main.cc new file mode 100644 index 0000000..461f401 --- /dev/null +++ b/peripheralmanager/daemon/main.cc
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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 <sysexits.h> + +#include <base/logging.h> +#include <base/macros.h> +#include <binderwrapper/binder_wrapper.h> +#include <brillo/binder_watcher.h> +#include <brillo/daemons/daemon.h> +#include <brillo/flag_helper.h> + +#include "peripheral_manager.h" + +namespace { + +class PeripheralManagerDaemon : public brillo::Daemon { + public: + PeripheralManagerDaemon() {}; + + ~PeripheralManagerDaemon() override = default; + + private: + // brillo::Daemon: + int OnInit() override { + int result = brillo::Daemon::OnInit(); + if (result != EX_OK) + return result; + + android::BinderWrapper::Create(); + if (!binder_watcher_.Init()) + return EX_OSERR; + if (!peripheral_manager_.Init()) + return EX_OSERR; + + LOG(INFO) << "Initialization complete"; + return EX_OK; + } + + brillo::BinderWatcher binder_watcher_; + android::PeripheralManager peripheral_manager_; + + DISALLOW_COPY_AND_ASSIGN(PeripheralManagerDaemon); +}; + +} // namespace + +int main(int argc, char *argv[]) { + brillo::FlagHelper::Init(argc, argv, "Peripheral management daemon"); + logging::InitLogging(logging::LoggingSettings()); + return PeripheralManagerDaemon().Run(); +}
diff --git a/peripheralmanager/daemon/peripheral_manager.cc b/peripheralmanager/daemon/peripheral_manager.cc new file mode 100644 index 0000000..ba8c6aa --- /dev/null +++ b/peripheralmanager/daemon/peripheral_manager.cc
@@ -0,0 +1,224 @@ +/* + * Copyright (C) 2015 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 "peripheral_manager.h" + +#include <base/logging.h> +#include <binderwrapper/binder_wrapper.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <hardware/hardware.h> +#include <hardware/peripheral_io.h> + +#include "gpio_driver_sysfs.h" +#include "gpio_manager.h" +#include "i2c_driver_i2cdev.h" +#include "i2c_manager.h" +#include "led_driver_sysfs.h" +#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 { + +// Gpio callbacks +static int RegisterGpioSysfs(const char* name, uint32_t index) { + return GpioManager::GetGpioManager()->RegisterGpioSysfs(name, index); +} + +static int SetGpioPinMux(const char* name, const char* source) { + return GpioManager::GetGpioManager()->SetPinMux(name, source); +} + +// Spi callbacks +static int RegisterSpiDevBus(const char* name, uint32_t bus, uint32_t cs) { + return SpiManager::GetSpiManager()->RegisterSpiDevBus(name, bus, cs); +} + +static int SetSpiPinMux(const char* name, const char* source) { + return SpiManager::GetSpiManager()->SetPinMux(name, source); +} + +// Led callbacks +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); +} + +static int SetI2cPinMux(const char* name, const char* source) { + return I2cManager::GetI2cManager()->SetPinMux(name, source); +} + +// Pin Mux callbacks. +static int RegisterPin(const char* name, + int gpio, + pin_mux_callbacks callbacks) { + return PinMuxManager::GetPinMuxManager()->RegisterPin(name, gpio, callbacks); +} + +static int RegisterPinGroup(const char* name, char** pins, size_t nr_pins) { + std::set<std::string> pins_set; + for (size_t i = 0; i < nr_pins; i++) + pins_set.emplace(pins[i]); + return PinMuxManager::GetPinMuxManager()->RegisterPinGroup(name, pins_set); +} + +static int RegisterSource(const char* name, char** groups, size_t nr_groups) { + std::set<std::string> groups_set; + for (size_t i = 0; i < nr_groups; i++) + groups_set.emplace(groups[i]); + return PinMuxManager::GetPinMuxManager()->RegisterSource(name, groups_set); +} + +static int RegisterSimpleSource(const char* name, + const char** pins, + size_t nr_pins) { + std::set<std::string> pins_set; + for (size_t i = 0; i < nr_pins; i++) + pins_set.emplace(pins[i]); + return PinMuxManager::GetPinMuxManager()->RegisterSimpleSource(name, + pins_set); +} + +} // namespace + +PeripheralManager::PeripheralManager() {} + +PeripheralManager::~PeripheralManager() = default; + +bool PeripheralManager::Init() { + if (!RegisterDrivers()) + return false; + + if (!InitHal()) + return false; + + String8 interface_desc(getInterfaceDescriptor()); + return BinderWrapper::Get()->RegisterService(interface_desc.string(), this); +} + +Status PeripheralManager::GetClient(const sp<IBinder>& lifeline, + sp<os::IPeripheralManagerClient>* client) { + sp<PeripheralManagerClient> c = new PeripheralManagerClient; + *client = c; + + lifeline->linkToDeath(this); + mapping_.emplace(lifeline.get(), c); + VLOG(1) << "client connecting " << mapping_.size(); + + return Status::ok(); +} + +void PeripheralManager::binderDied(const wp<IBinder>& who) { + mapping_.erase(who.unsafe_get()); + VLOG(1) << "client disconnecting " << mapping_.size(); +} + +bool PeripheralManager::RegisterDrivers() { + if (!SpiManager::GetSpiManager()->RegisterDriver( + std::unique_ptr<SpiDriverInfoBase>( + new SpiDriverInfo<SpiDriverSpiDev, CharDeviceFactory*>( + nullptr)))) { + LOG(ERROR) << "Failed to load driver: SpiDriverSpiDev"; + return false; + } + if (!I2cManager::GetI2cManager()->RegisterDriver( + std::unique_ptr<I2cDriverInfoBase>( + new I2cDriverInfo<I2cDriverI2cDev, CharDeviceFactory*>( + nullptr)))) { + LOG(ERROR) << "Failed to load driver: I2cDriverI2cDev"; + return false; + } + if (!GpioManager::GetGpioManager()->RegisterDriver( + std::unique_ptr<GpioDriverInfoBase>( + new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr)))) { + LOG(ERROR) << "Failed to load driver: GpioDriverSysfs"; + return false; + } + if (!LedManager::GetLedManager()->RegisterDriver( + std::unique_ptr<LedDriverInfoBase>( + new LedDriverInfo<LedDriverSysfs, std::string*>(nullptr)))) { + 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; +} + +bool PeripheralManager::InitHal() { + const hw_module_t* module = nullptr; + if (hw_get_module(PERIPHERAL_IO_HARDWARE_MODULE_ID, &module) != 0) { + LOG(ERROR) << "Failed to load HAL" << module; + return true; + } + + const peripheral_io_module_t* peripheral_module = + reinterpret_cast<const peripheral_io_module_t*>(module); + + struct peripheral_registration_cb_t callbacks = { + // Gpio + .register_gpio_sysfs = RegisterGpioSysfs, + .set_gpio_pin_mux = SetGpioPinMux, + + // Spi + .register_spi_dev_bus = RegisterSpiDevBus, + .set_spi_pin_mux = SetSpiPinMux, + + // 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, + + // Pin Mux + .register_pin = RegisterPin, + .register_pin_group = RegisterPinGroup, + .register_source = RegisterSource, + .register_simple_source = RegisterSimpleSource, + }; + + peripheral_module->register_devices(peripheral_module, &callbacks); + + return true; +} + +} // namespace android
diff --git a/peripheralmanager/daemon/peripheral_manager.h b/peripheralmanager/daemon/peripheral_manager.h new file mode 100644 index 0000000..8b5568f --- /dev/null +++ b/peripheralmanager/daemon/peripheral_manager.h
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 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_PERIPHERAL_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_PERIPHERAL_MANAGER_H_ + +#include <map> + +#include <base/macros.h> + +#include <android/os/BnPeripheralManager.h> + +#include "peripheral_manager_client.h" + +using android::binder::Status; +using android::os::BnPeripheralManager; + +namespace android { + +class PeripheralManager : public BnPeripheralManager, + public BnPeripheralManager::DeathRecipient { + public: + PeripheralManager(); + ~PeripheralManager(); + + bool Init(); + + // IPeripheralManager Interface + Status GetClient(const sp<IBinder>& lifeline, + sp<os::IPeripheralManagerClient>* _aidl_return); + + void binderDied(const wp<IBinder>& who) override; + + private: + bool InitHal(); + bool RegisterDrivers(); + + std::map<IBinder*, sp<PeripheralManagerClient>> mapping_; + + DISALLOW_COPY_AND_ASSIGN(PeripheralManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_PERIPHERAL_MANAGER_H_
diff --git a/peripheralmanager/daemon/peripheral_manager_client.cc b/peripheralmanager/daemon/peripheral_manager_client.cc new file mode 100644 index 0000000..8dc30ea --- /dev/null +++ b/peripheralmanager/daemon/peripheral_manager_client.cc
@@ -0,0 +1,566 @@ +/* + * 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 "peripheral_manager_client.h" + +#include <base/logging.h> + +namespace android { + +PeripheralManagerClient::PeripheralManagerClient() {} +PeripheralManagerClient::~PeripheralManagerClient() {} + +Status PeripheralManagerClient::ListGpio(std::vector<std::string>* gpios) { + *gpios = GpioManager::GetGpioManager()->GetGpioPins(); + return Status::ok(); +} + +Status PeripheralManagerClient::OpenGpio(const std::string& name) { + if (!GpioManager::GetGpioManager()->HasGpio(name)) + return Status::fromServiceSpecificError(ENODEV); + + auto gpio = GpioManager::GetGpioManager()->OpenGpioPin(name); + if (!gpio) { + LOG(ERROR) << "Failed to open GPIO " << name; + return Status::fromServiceSpecificError(EBUSY); + } + + gpios_.emplace(name, std::move(gpio)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseGpio(const std::string& name) { + gpios_.erase(name); + return Status::ok(); +} + +Status PeripheralManagerClient::SetGpioEdge(const std::string& name, int type) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->SetEdgeType(GpioEdgeType(type))) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SetGpioActiveType(const std::string& name, + int type) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->SetActiveType(GpioActiveType(type))) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SetGpioDirection(const std::string& name, + int direction) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->SetDirection(GpioDirection(direction))) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SetGpioValue(const std::string& name, + bool value) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->SetValue(value)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::GetGpioValue(const std::string& name, + bool* value) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->GetValue(value)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::GetGpioPollingFd( + const std::string& name, + ::android::base::unique_fd* fd) { + if (!gpios_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (gpios_.find(name)->second->GetPollingFd(fd)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::ListSpiBuses(std::vector<std::string>* buses) { + *buses = SpiManager::GetSpiManager()->GetSpiDevBuses(); + return Status::ok(); +} + +Status PeripheralManagerClient::OpenSpiDevice(const std::string& name) { + if (!SpiManager::GetSpiManager()->HasSpiDevBus(name)) + return Status::fromServiceSpecificError(ENODEV); + + std::unique_ptr<SpiDevice> device = + SpiManager::GetSpiManager()->OpenSpiDevice(name); + + if (!device) { + LOG(ERROR) << "Failed to open device " << name; + return Status::fromServiceSpecificError(EBUSY); + } + + spi_devices_.emplace(name, std::move(device)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseSpiDevice(const std::string& name) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + spi_devices_.erase(name); + return Status::ok(); +} + +Status PeripheralManagerClient::SpiDeviceWriteByte(const std::string& name, + int8_t byte) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (spi_devices_.find(name)->second->WriteByte(byte)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceWriteBuffer( + const std::string& name, + const std::vector<uint8_t>& buffer) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (spi_devices_.find(name)->second->WriteBuffer(buffer.data(), + buffer.size())) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceTransfer( + const std::string& name, + const std::unique_ptr<std::vector<uint8_t>>& tx_data, + std::unique_ptr<std::vector<uint8_t>>* rx_data, + int size) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (!rx_data) { + if (spi_devices_.find(name)->second->Transfer(tx_data->data(), nullptr, + size)) { + return Status::ok(); + } + } else { + rx_data->reset(new std::vector<uint8_t>(size)); + if (spi_devices_.find(name)->second->Transfer(tx_data->data(), + (*rx_data)->data(), size)) { + return Status::ok(); + } + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceSetMode(const std::string& name, + int mode) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (spi_devices_.find(name)->second->SetMode(SpiMode(mode))) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceSetFrequency(const std::string& name, + int frequency_hz) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (frequency_hz > 0 && + spi_devices_.find(name)->second->SetFrequency(frequency_hz)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceSetBitJustification( + const std::string& name, + bool lsb_first) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (spi_devices_.find(name)->second->SetBitJustification(lsb_first)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceSetBitsPerWord(const std::string& name, + int nbits) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (spi_devices_.find(name)->second->SetBitsPerWord(nbits)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::SpiDeviceSetDelay(const std::string& name, + int delay_usecs) { + if (!spi_devices_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + // |delay_usecs| must be positive and fit in an unsigned 16 bit. + if (delay_usecs < 0 || delay_usecs > INT16_MAX) + return Status::fromServiceSpecificError(EINVAL); + + if (spi_devices_.find(name)->second->SetDelay( + static_cast<uint16_t>(delay_usecs))) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::ListLeds(std::vector<std::string>* leds) { + *leds = LedManager::GetLedManager()->GetLeds(); + return Status::ok(); +} + +Status PeripheralManagerClient::OpenLed(const std::string& name) { + if (!LedManager::GetLedManager()->HasLed(name)) { + return Status::fromServiceSpecificError(ENODEV); + } + auto led = LedManager::GetLedManager()->OpenLed(name); + if (!led) { + LOG(ERROR) << "Failed to open LED " << name; + return Status::fromServiceSpecificError(EBUSY); + } + + leds_.emplace(name, std::move(led)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseLed(const std::string& name) { + leds_.erase(name); + return Status::ok(); +} + +Status PeripheralManagerClient::LedGetBrightness(const std::string& name, + int* brightness) { + if (!leds_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + uint32_t temp; + if (leds_.find(name)->second->GetBrightness(&temp)) { + *brightness = temp; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::LedGetMaxBrightness(const std::string& name, + int* max_brightness) { + if (!leds_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + uint32_t temp; + if (leds_.find(name)->second->GetMaxBrightness(&temp)) { + *max_brightness = temp; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::LedSetBrightness(const std::string& name, + int brightness) { + if (!leds_.count(name)) + return Status::fromServiceSpecificError(EPERM); + + if (leds_.find(name)->second->SetBrightness(brightness)) + return Status::ok(); + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::ListI2cBuses(std::vector<std::string>* buses) { + *buses = I2cManager::GetI2cManager()->GetI2cDevBuses(); + + return Status::ok(); +} + +Status PeripheralManagerClient::OpenI2cDevice(const std::string& name, + int32_t address) { + if (!I2cManager::GetI2cManager()->HasI2cDevBus(name)) + return Status::fromServiceSpecificError(ENODEV); + + std::unique_ptr<I2cDevice> device = + I2cManager::GetI2cManager()->OpenI2cDevice(name, address); + + if (!device) { + LOG(ERROR) << "Failed to open device " << name; + return Status::fromServiceSpecificError(EBUSY); + } + std::pair<std::string, uint32_t> i2c_dev(name, address); + i2c_devices_.emplace(i2c_dev, std::move(device)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseI2cDevice(const std::string& name, + int32_t address) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + i2c_devices_.erase({name, address}); + return Status::ok(); +} + +Status PeripheralManagerClient::I2cRead(const std::string& name, + int32_t address, + std::vector<uint8_t>* data, + int32_t size, + int32_t* bytes_read) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + if (size < 0) { + return Status::fromServiceSpecificError(EINVAL); + } + data->resize(size); + + uint32_t* nread = reinterpret_cast<uint32_t*>(bytes_read); + int32_t ret = i2c_devices_.find({name, address}) + ->second->Read(data->data(), data->size(), nread); + data->resize(*nread); + + return ret == 0 ? Status::ok() : Status::fromServiceSpecificError(ret); +} + +Status PeripheralManagerClient::I2cReadRegByte(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + uint8_t tmp_val = 0; + if (i2c_devices_.find({name, address})->second->ReadRegByte(reg, &tmp_val) == + 0) { + *val = tmp_val; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::I2cReadRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + uint16_t tmp_val = 0; + if (i2c_devices_.find({name, address})->second->ReadRegWord(reg, &tmp_val) == + 0) { + *val = tmp_val; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::I2cReadRegBuffer(const std::string& name, + int32_t address, + int32_t reg, + std::vector<uint8_t>* data, + int32_t size, + int32_t* bytes_read) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + if (size < 0) { + return Status::fromServiceSpecificError(EINVAL); + } + data->resize(size); + + uint32_t* nread = reinterpret_cast<uint32_t*>(bytes_read); + int32_t ret = + i2c_devices_.find({name, address}) + ->second->ReadRegBuffer(reg, data->data(), data->size(), nread); + + data->resize(*nread); + return ret == 0 ? Status::ok() : Status::fromServiceSpecificError(ret); +} + +Status PeripheralManagerClient::I2cWrite(const std::string& name, + int32_t address, + const std::vector<uint8_t>& data, + int32_t* bytes_written) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + int ret = i2c_devices_.find({name, address}) + ->second->Write(data.data(), + data.size(), + reinterpret_cast<uint32_t*>(bytes_written)); + + return ret == 0 ? Status::ok() : Status::fromServiceSpecificError(ret); +} + +Status PeripheralManagerClient::I2cWriteRegByte(const std::string& name, + int32_t address, + int32_t reg, + int8_t val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + if (i2c_devices_.find({name, address})->second->WriteRegByte(reg, val) == 0) { + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::I2cWriteRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + if (i2c_devices_.find({name, address})->second->WriteRegWord(reg, val) == 0) { + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::I2cWriteRegBuffer( + const std::string& name, + int32_t address, + int32_t reg, + const std::vector<uint8_t>& data, + int32_t* bytes_written) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + int32_t ret = + i2c_devices_.find({name, address}) + ->second->WriteRegBuffer(reg, + data.data(), + data.size(), + reinterpret_cast<uint32_t*>(bytes_written)); + + return ret == 0 ? Status::ok() : Status::fromServiceSpecificError(ret); +} + +Status PeripheralManagerClient::ListUartDevices( + std::vector<std::string>* devices) { + *devices = UartManager::GetManager()->GetDevicesList(); + return Status::ok(); +} + +Status PeripheralManagerClient::OpenUartDevice(const std::string& name) { + if (!UartManager::GetManager()->HasUartDevice(name)) + return Status::fromServiceSpecificError(ENODEV); + + auto uart_device = UartManager::GetManager()->OpenUartDevice(name); + if (!uart_device) { + LOG(ERROR) << "Failed to open UART device " << name; + return Status::fromServiceSpecificError(EBUSY); + } + + uart_devices_.emplace(name, std::move(uart_device)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseUartDevice(const std::string& name) { + return uart_devices_.erase(name) ? Status::ok() + : Status::fromServiceSpecificError(EPERM); +} + +Status PeripheralManagerClient::SetUartDeviceBaudrate(const std::string& name, + int32_t baudrate) { + auto uart_device = uart_devices_.find(name); + if (uart_device == uart_devices_.end()) + return Status::fromServiceSpecificError(EPERM); + + if (baudrate < 0) + return Status::fromServiceSpecificError(EINVAL); + + int ret = uart_device->second->SetBaudrate(static_cast<uint32_t>(baudrate)); + + if (ret) + return Status::fromServiceSpecificError(ret); + + return Status::ok(); +} + +Status PeripheralManagerClient::UartDeviceWrite( + const std::string& name, + const std::vector<uint8_t>& data, + int32_t* bytes_written) { + auto uart_device = uart_devices_.find(name); + if (uart_device == uart_devices_.end()) + return Status::fromServiceSpecificError(EPERM); + + int ret = uart_device->second->Write( + data, reinterpret_cast<uint32_t*>(bytes_written)); + + if (ret) + return Status::fromServiceSpecificError(ret); + + return Status::ok(); +} + +Status PeripheralManagerClient::UartDeviceRead(const std::string& name, + std::vector<uint8_t>* data, + int size, + int* bytes_read) { + auto uart_device = uart_devices_.find(name); + if (uart_device == uart_devices_.end()) + return Status::fromServiceSpecificError(EPERM); + + int ret = uart_device->second->Read( + data, size, reinterpret_cast<uint32_t*>(bytes_read)); + + if (ret) + return Status::fromServiceSpecificError(ret); + + return Status::ok(); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/peripheral_manager_client.h b/peripheralmanager/daemon/peripheral_manager_client.h new file mode 100644 index 0000000..ee9abe4 --- /dev/null +++ b/peripheralmanager/daemon/peripheral_manager_client.h
@@ -0,0 +1,197 @@ +/* + * 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_PERIPHERAL_MANAGER_CLIENT_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_PERIPHERAL_MANAGER_CLIENT_H_ + +#include <map> +#include <memory> +#include <string> + +#include <base/macros.h> + +#include <android/os/BnPeripheralManagerClient.h> + +#include "gpio_manager.h" +#include "i2c_manager.h" +#include "led_manager.h" +#include "spi_manager.h" +#include "uart_manager.h" + +using android::binder::Status; +using android::os::BnPeripheralManagerClient; + +namespace android { + +class PeripheralManagerClient : public BnPeripheralManagerClient { + public: + PeripheralManagerClient(); + ~PeripheralManagerClient(); + + // Gpio functions. + Status ListGpio(std::vector<std::string>* gpios) override; + + Status OpenGpio(const std::string& name) override; + + Status ReleaseGpio(const std::string& name) override; + + Status SetGpioEdge(const std::string& name, int type) override; + + Status SetGpioActiveType(const std::string& name, int type) override; + + Status SetGpioDirection(const std::string& name, + int direction) override; + + Status SetGpioValue(const std::string& name, bool value) override; + + Status GetGpioValue(const std::string& name, bool* value) override; + + Status GetGpioPollingFd(const std::string& name, + ::android::base::unique_fd* fd) override; + + // Spi functions. + Status ListSpiBuses(std::vector<std::string>* buses) override; + + Status OpenSpiDevice(const std::string& name) override; + + Status ReleaseSpiDevice(const std::string& name) override; + + Status SpiDeviceWriteByte(const std::string& name, + int8_t byte) override; + + Status SpiDeviceWriteBuffer( + const std::string& name, + const std::vector<uint8_t>& buffer) override; + + Status SpiDeviceTransfer( + const std::string& name, + const std::unique_ptr<std::vector<uint8_t>>& tx_data, + std::unique_ptr<std::vector<uint8_t>>* rx_data, + int len) override; + + Status SpiDeviceSetMode(const std::string& name, int mode) override; + + Status SpiDeviceSetFrequency(const std::string& name, + int frequency_hz) override; + + Status SpiDeviceSetBitJustification(const std::string& name, + bool lsb_first) override; + + Status SpiDeviceSetBitsPerWord(const std::string& name, + int nbits) override; + + Status SpiDeviceSetDelay(const std::string& name, + int delay_usecs) override; + + // Led functions. + Status ListLeds(std::vector<std::string>* leds) override; + + Status OpenLed(const std::string& name) override; + + Status ReleaseLed(const std::string& name) override; + + Status LedGetBrightness(const std::string& name, + int* brightness) override; + Status LedGetMaxBrightness(const std::string& name, + int* max_brightness) override; + Status LedSetBrightness(const std::string& name, + int brightness) override; + + // I2c functions. + Status ListI2cBuses(std::vector<std::string>* buses) override; + + Status OpenI2cDevice(const std::string& name, + int32_t address) override; + + Status ReleaseI2cDevice(const std::string& name, + int32_t address) override; + + Status I2cRead(const std::string& name, + int32_t address, + std::vector<uint8_t>* data, + int32_t size, + int32_t* bytes_read) override; + + Status I2cReadRegByte(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) override; + + Status I2cReadRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) override; + + Status I2cReadRegBuffer(const std::string& name, + int32_t address, + int32_t reg, + std::vector<uint8_t>* data, + int32_t size, + int32_t* bytes_read) override; + + Status I2cWrite(const std::string& name, + int32_t address, + const std::vector<uint8_t>& data, + int32_t* bytes_written) override; + + Status I2cWriteRegByte(const std::string& name, + int32_t address, + int32_t reg, + int8_t val) override; + + Status I2cWriteRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t val) override; + + Status I2cWriteRegBuffer(const std::string& name, + int32_t address, + int32_t reg, + const std::vector<uint8_t>& data, + int32_t* bytes_written) override; + + // Uart functions. + Status ListUartDevices(std::vector<std::string>* devices) override; + + Status OpenUartDevice(const std::string& name) override; + + Status ReleaseUartDevice(const std::string& name) override; + + Status SetUartDeviceBaudrate(const std::string& name, + int32_t baudrate) override; + + Status UartDeviceWrite(const std::string& name, + const std::vector<uint8_t>& data, + int* bytes_written) override; + + Status UartDeviceRead(const std::string& name, + std::vector<uint8_t>* data, + int size, + int* bytes_read) override; + + private: + std::map<std::string, std::unique_ptr<GpioPin>> gpios_; + std::map<std::pair<std::string, uint32_t>, std::unique_ptr<I2cDevice>> + i2c_devices_; + std::map<std::string, std::unique_ptr<SpiDevice>> spi_devices_; + std::map<std::string, std::unique_ptr<Led>> leds_; + std::map<std::string, std::unique_ptr<UartDevice>> uart_devices_; + DISALLOW_COPY_AND_ASSIGN(PeripheralManagerClient); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_PERIPHERAL_MANAGER_CLIENT_H_
diff --git a/peripheralmanager/daemon/peripheralman.rc b/peripheralmanager/daemon/peripheralman.rc new file mode 100644 index 0000000..578fac5 --- /dev/null +++ b/peripheralmanager/daemon/peripheralman.rc
@@ -0,0 +1,4 @@ +service peripheralman /system/bin/peripheralman + class main + user root + group system
diff --git a/peripheralmanager/daemon/pin_mux_manager.cc b/peripheralmanager/daemon/pin_mux_manager.cc new file mode 100644 index 0000000..96d7371 --- /dev/null +++ b/peripheralmanager/daemon/pin_mux_manager.cc
@@ -0,0 +1,167 @@ +/* + * 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 "pin_mux_manager.h" + +#include <base/logging.h> + +namespace android { + +std::unique_ptr<PinMuxManager> g_pin_mux_manager; + +PinMuxManager::PinMuxManager() {} + +PinMuxManager::~PinMuxManager() {} + +// static +PinMuxManager* PinMuxManager::GetPinMuxManager() { + if (!g_pin_mux_manager) { + g_pin_mux_manager.reset(new PinMuxManager()); + } + return g_pin_mux_manager.get(); +} + +bool PinMuxManager::RegisterPin(std::string name, + bool gpio, + pin_mux_callbacks callbacks) { + if (pins_.count(name)) + return false; + pins_[name] = {false, gpio, callbacks}; + return true; +} + +bool PinMuxManager::RegisterPinGroup(std::string name, + std::set<std::string> pins) { + if (groups_.count(name)) + return false; + + // Check each pin is valid. + for (auto& p : pins) { + if (!pins_.count(p)) + return false; + } + groups_[name] = pins; + return true; +} + +bool PinMuxManager::RegisterSource(std::string name, + std::set<std::string> groups) { + if (sources_.count(name)) + return false; + + // Check each group is valid. + for (auto& g : groups) { + if (!groups_.count(g)) + return false; + } + sources_[name] = groups; + return true; +} + +bool PinMuxManager::RegisterSimpleSource(std::string name, + std::set<std::string> pins) { + if (!RegisterPinGroup(name, pins)) + return false; + if (!RegisterSource(name, {name})) { + // TODO(leecam): Unregister Group + return false; + } + return true; +} + +bool PinMuxManager::SetSource(std::string name, std::string group) { + if (!sources_.count(name)) + return false; + + if (!sources_[name].count(group)) + return false; + + // Check to make sure each pin is not in use. + for (auto& p : groups_[group]) { + if (pins_[p].in_use) + return false; + } + + // Enable each Pin + for (auto& p : groups_[group]) { + pins_[p].in_use = true; + + // TODO(leecam): Handle failures here!!! + if (pins_[p].callbacks.mux_cb) + pins_[p].callbacks.mux_cb(p.c_str(), name.c_str()); + } + + return true; +} + +void PinMuxManager::ReleaseSource(std::string name, std::string group) { + if (!sources_.count(name)) + return; + if (!sources_[name].count(group)) + return; + for (auto& p : groups_[group]) { + if (!pins_[p].in_use) { + LOG(WARNING) << "Releasig Pin " << p << " that is not in use."; + } + pins_[p].in_use = false; + } +} + +bool PinMuxManager::SetSimpleSource(std::string name) { + return SetSource(name, name); +} + +bool PinMuxManager::SetGpio(std::string name) { + if (!pins_.count(name)) { + LOG(WARNING) << "PinMuxManager: Pin not found " << name; + return false; + } + if (pins_[name].in_use) { + LOG(WARNING) << "PinMuxManager: Pin in use " << name; + return false; + } + if (pins_[name].callbacks.mux_cb) { + if (!pins_[name].callbacks.mux_cb(name.c_str(), nullptr)) + return false; + } + pins_[name].in_use = true; + return true; +} + +void PinMuxManager::ReleaseGpio(std::string name) { + if (!pins_.count(name)) + return; + pins_[name].in_use = false; +} + +bool PinMuxManager::SetGpioDirection(std::string name, bool output) { + if (!pins_.count(name)) { + LOG(WARNING) << "SetGpioDirection pin not found " << name; + return false; + } + // Check if not in use - this should maybe be a DCHECK as + // it shoudn't be able to happen. + if (!pins_[name].in_use) { + LOG(WARNING) << "SetGpioDirection not in use " << name; + return false; + } + if (pins_[name].callbacks.direction_cb) + return pins_[name].callbacks.direction_cb(name.c_str(), output); + + return true; +} + +} // namespace android \ No newline at end of file
diff --git a/peripheralmanager/daemon/pin_mux_manager.h b/peripheralmanager/daemon/pin_mux_manager.h new file mode 100644 index 0000000..e18ec4a --- /dev/null +++ b/peripheralmanager/daemon/pin_mux_manager.h
@@ -0,0 +1,81 @@ +/* + * 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_PIN_MUX_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_PIN_MUX_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include <hardware/peripheral_io.h> + +namespace android { + +struct Pin { + bool in_use; + bool gpio; + pin_mux_callbacks callbacks; +}; + +class PinMuxManager { + public: + friend class PinMuxManagerTest; + ~PinMuxManager(); + + // Get the singleton. + static PinMuxManager* GetPinMuxManager(); + + // The following Register* functions as used to configure + // the pin mux configuation. These are called by the during + // BSP setup, using the HAL. + bool RegisterPin(std::string name, bool gpio, pin_mux_callbacks callbacks); + bool RegisterPinGroup(std::string name, std::set<std::string> pins); + bool RegisterSource(std::string name, std::set<std::string> groups); + // Helper that registers a source with a default group of the same name. + bool RegisterSimpleSource(std::string name, std::set<std::string> pins); + + // Called by the device managers, e.g SpiManager. + // These are used to configure the pin muxing at runtime. + bool SetSource(std::string name, std::string group); + bool SetSimpleSource(std::string name); + void ReleaseSource(std::string name, std::string group); + + // Used by the GpioManager to enable Gpio pins. + bool SetGpio(std::string name); + void ReleaseGpio(std::string name); + bool SetGpioDirection(std::string name, bool output); + + private: + // Private constuctor as this class is accessed via a singleton. + PinMuxManager(); + + std::map<std::string, Pin> pins_; + std::map<std::string, std::set<std::string>> groups_; + std::map<std::string, std::set<std::string>> sources_; + + DISALLOW_COPY_AND_ASSIGN(PinMuxManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_PIN_MUX_MANAGER_H_
diff --git a/peripheralmanager/daemon/pin_mux_manager_unittest.cc b/peripheralmanager/daemon/pin_mux_manager_unittest.cc new file mode 100644 index 0000000..aa0073c --- /dev/null +++ b/peripheralmanager/daemon/pin_mux_manager_unittest.cc
@@ -0,0 +1,87 @@ +/* + * 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 <stdio.h> + +#include <gtest/gtest.h> + +#include "pin_mux_manager.h" + +namespace android { + +class PinMuxManagerTest : public ::testing::Test { + public: + PinMuxManagerTest() {} + ~PinMuxManagerTest() = default; + + protected: + PinMuxManager manager; + pin_mux_callbacks callbacks = {nullptr, nullptr}; +}; + +TEST_F(PinMuxManagerTest, RegisterPin) { + ASSERT_TRUE(manager.RegisterPin("IO1", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO2", true, callbacks)); + + ASSERT_FALSE(manager.RegisterPin("IO1", true, callbacks)); + ASSERT_FALSE(manager.RegisterPin("IO2", true, callbacks)); +} + +TEST_F(PinMuxManagerTest, RegisterGroup) { + ASSERT_TRUE(manager.RegisterPin("IO1", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO2", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO3", true, callbacks)); + + ASSERT_TRUE(manager.RegisterPinGroup("Group1", {"IO1", "IO2", "IO3"})); + ASSERT_TRUE(manager.RegisterPinGroup("Group2", {"IO1"})); + ASSERT_FALSE(manager.RegisterPinGroup("Group1", {"IO1", "IO2", "IO3"})); + ASSERT_FALSE(manager.RegisterPinGroup("Group3", {"IO1", "BAD", "IO3"})); +} + +TEST_F(PinMuxManagerTest, RegisterSource) { + ASSERT_TRUE(manager.RegisterPin("IO1", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO2", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO3", true, callbacks)); + + ASSERT_TRUE(manager.RegisterPinGroup("Group1", {"IO1", "IO2", "IO3"})); + ASSERT_TRUE(manager.RegisterPinGroup("Group2", {"IO1"})); + + ASSERT_TRUE(manager.RegisterSource("Source1", {"Group1"})); + ASSERT_TRUE(manager.RegisterSource("Source2", {"Group1", "Group2"})); + + ASSERT_FALSE(manager.RegisterSource("Source3", {"Bad"})); + + ASSERT_FALSE(manager.RegisterSource("Source1", {"Group1"})); +} + +TEST_F(PinMuxManagerTest, SetSource) { + ASSERT_TRUE(manager.RegisterPin("IO1", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO2", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO3", true, callbacks)); + ASSERT_TRUE(manager.RegisterPin("IO4", true, callbacks)); + + ASSERT_TRUE(manager.RegisterPinGroup("Group1", {"IO1", "IO2", "IO3"})); + ASSERT_TRUE(manager.RegisterPinGroup("Group2", {"IO4"})); + + ASSERT_TRUE(manager.RegisterSource("Source1", {"Group1", "Group2"})); + + ASSERT_TRUE(manager.SetSource("Source1", "Group1")); + ASSERT_TRUE(manager.SetSource("Source1", "Group2")); +} + +// TODO(leecam): Write lots more tetsts :) + +} // namespace android \ No newline at end of file
diff --git a/peripheralmanager/daemon/spi_driver.h b/peripheralmanager/daemon/spi_driver.h new file mode 100644 index 0000000..44ecc90 --- /dev/null +++ b/peripheralmanager/daemon/spi_driver.h
@@ -0,0 +1,73 @@ +/* + * 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_SPI_DRIVER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_DRIVER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" + +namespace android { + +class SpiDriverInterface { + public: + SpiDriverInterface() {} + virtual ~SpiDriverInterface() {} + + // TODO(leecam): Init should have generic params. + virtual bool Init(uint32_t bus_id, uint32_t cs) = 0; + virtual bool Transfer(const void* tx_data, void* rx_data, size_t len) = 0; + virtual bool SetFrequency(uint32_t speed_hz) = 0; + virtual bool SetMode(SpiMode mode) = 0; + virtual bool SetBitJustification(bool lsb_first) = 0; + virtual bool SetBitsPerWord(uint8_t bits_per_word) = 0; + virtual bool SetDelay(uint16_t delay_usecs) = 0; +}; + +class SpiDriverInfoBase { + public: + SpiDriverInfoBase() {} + virtual ~SpiDriverInfoBase() {} + + virtual std::string Compat() = 0; + virtual std::unique_ptr<SpiDriverInterface> Probe() = 0; +}; + +template <class T, class PARAM> +class SpiDriverInfo : public SpiDriverInfoBase { + public: + explicit SpiDriverInfo(PARAM param) : param_(param) {} + ~SpiDriverInfo() override {} + + std::string Compat() override { return T::Compat(); } + + std::unique_ptr<SpiDriverInterface> Probe() override { + return std::unique_ptr<SpiDriverInterface>(new T(param_)); + } + + private: + PARAM param_; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_DRIVER_H_
diff --git a/peripheralmanager/daemon/spi_driver_spidev.cc b/peripheralmanager/daemon/spi_driver_spidev.cc new file mode 100644 index 0000000..2ac4844 --- /dev/null +++ b/peripheralmanager/daemon/spi_driver_spidev.cc
@@ -0,0 +1,172 @@ +/* + * 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 "spi_driver_spidev.h" + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/spi/spidev.h> +#include <string> + +#include <base/logging.h> + +namespace android { +namespace { + +const char kSpiDevPath[] = "/dev/spidev"; + +} // namespace + +SpiDriverSpiDev::SpiDriverSpiDev(CharDeviceFactory* char_device_factory) + : fd_(-1), char_device_factory_(char_device_factory) {} + +SpiDriverSpiDev::~SpiDriverSpiDev() { + if (fd_ >= 0 && char_interface_ != nullptr) { + char_interface_->Close(fd_); + } +} + +bool SpiDriverSpiDev::Init(uint32_t bus_id, uint32_t cs) { + if (fd_ >= 0) { + return false; + } + + // 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(); + } + + std::string path = + kSpiDevPath + std::to_string(bus_id) + "." + std::to_string(cs); + + int fd = char_interface_->Open(path.c_str(), O_RDWR); + if (fd < 0) + return false; + + fd_ = fd; + + // Set the default speed to the max + uint32_t max_freq = 0; + if (!GetMaxFrequency(&max_freq)) { + char_interface_->Close(fd_); + fd_ = -1; + return false; + } + speed_hz_ = max_freq; + + // Default to 0 microseconds delay between transfers. + delay_usecs_ = 0; + + // Default to 8 bits per word. + bits_per_word_ = 8; + + return true; +} + +bool SpiDriverSpiDev::Transfer(const void* tx_data, void* rx_data, size_t len) { + struct spi_ioc_transfer msg; + memset(&msg, 0, sizeof(msg)); + + msg.tx_buf = (unsigned long)tx_data; + msg.rx_buf = (unsigned long)rx_data; + msg.speed_hz = speed_hz_; + msg.bits_per_word = bits_per_word_; + msg.delay_usecs = delay_usecs_; + msg.len = len; + + if (char_interface_->Ioctl(fd_, SPI_IOC_MESSAGE(1), &msg) < 0) { + PLOG(ERROR) << "SPI Transfer IOCTL Failed"; + return false; + } + return true; +} + +bool SpiDriverSpiDev::SetFrequency(uint32_t speed_hz) { + if (fd_ < 0) + return false; + // Get the max speed and ensure speed_hz is less than it. + uint32_t max_speed = 0; + if (!GetMaxFrequency(&max_speed)) + return false; + if (speed_hz > max_speed) + speed_hz = max_speed; + + speed_hz_ = speed_hz; + return true; +} + +bool SpiDriverSpiDev::GetMaxFrequency(uint32_t* max_freq) { + if (char_interface_->Ioctl(fd_, SPI_IOC_RD_MAX_SPEED_HZ, max_freq) < 0) { + PLOG(ERROR) << "Failed to get spi max freq"; + return false; + } + return true; +} + +bool SpiDriverSpiDev::SetMode(SpiMode mode) { + uint8_t k_mode = 0; + switch (mode) { + case kMode0: + k_mode = SPI_MODE_0; + break; + case kMode1: + k_mode = SPI_MODE_1; + break; + case kMode2: + k_mode = SPI_MODE_2; + break; + case kMode3: + k_mode = SPI_MODE_3; + break; + } + + if (char_interface_->Ioctl(fd_, SPI_IOC_WR_MODE, &k_mode) < 0) { + PLOG(ERROR) << "Failed to set mode"; + return false; + } + + return true; +} + +bool SpiDriverSpiDev::SetBitJustification(bool lsb_first) { + uint8_t k_lsb_first = lsb_first; + if (char_interface_->Ioctl(fd_, SPI_IOC_WR_LSB_FIRST, &k_lsb_first) < 0) { + PLOG(ERROR) << "Failed to set bit justifcation"; + return false; + } + return true; +} + +bool SpiDriverSpiDev::SetBitsPerWord(uint8_t bits_per_word) { + if (char_interface_->Ioctl(fd_, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < + 0) { + PLOG(ERROR) << "Failed to set bits per word"; + return false; + } + bits_per_word_ = bits_per_word; + return true; +} + +bool SpiDriverSpiDev::SetDelay(uint16_t delay_usecs) { + delay_usecs_ = delay_usecs; + return true; +} + +} // namespace android
diff --git a/peripheralmanager/daemon/spi_driver_spidev.h b/peripheralmanager/daemon/spi_driver_spidev.h new file mode 100644 index 0000000..67f3bd5 --- /dev/null +++ b/peripheralmanager/daemon/spi_driver_spidev.h
@@ -0,0 +1,64 @@ +/* + * 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_SPI_DRIVER_SPIDEV_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_DRIVER_SPIDEV_H_ + +#include <stdint.h> + +#include <memory> + +#include <base/macros.h> + +#include "char_device.h" +#include "spi_driver.h" + +namespace android { + +class SpiDriverSpiDev : public SpiDriverInterface { + public: + explicit SpiDriverSpiDev(CharDeviceFactory* char_device_factory); + ~SpiDriverSpiDev(); + + static std::string Compat() { return "SPIDEV"; } + + bool Init(uint32_t bus_id, uint32_t cs) override; + bool Transfer(const void* tx_data, void* rx_data, size_t len) override; + bool SetFrequency(uint32_t speed_hz) override; + bool SetMode(SpiMode mode) override; + bool SetBitJustification(bool lsb_first) override; + bool SetBitsPerWord(uint8_t bits_per_word) override; + bool SetDelay(uint16_t delay_usecs) override; + + private: + bool GetMaxFrequency(uint32_t* max_freq); + + int fd_; + uint32_t bits_per_word_; + uint32_t speed_hz_; + uint16_t delay_usecs_; + std::unique_ptr<CharDeviceInterface> char_interface_; + + // Used for unit testing and is null in production. + // Ownership is in the test and outlives this class. + CharDeviceFactory* char_device_factory_; + + DISALLOW_COPY_AND_ASSIGN(SpiDriverSpiDev); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_DEVICE_H_
diff --git a/peripheralmanager/daemon/spi_manager.cc b/peripheralmanager/daemon/spi_manager.cc new file mode 100644 index 0000000..4e11c84 --- /dev/null +++ b/peripheralmanager/daemon/spi_manager.cc
@@ -0,0 +1,124 @@ +/* + * 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 "spi_manager.h" + +#include "pin_mux_manager.h" + +namespace android { + +std::unique_ptr<SpiManager> g_spi_manager; + +SpiManager::SpiManager() {} + +SpiManager::~SpiManager() {} + +// static +SpiManager* SpiManager::GetSpiManager() { + if (!g_spi_manager) { + g_spi_manager.reset(new SpiManager()); + } + return g_spi_manager.get(); +} + +// static +void SpiManager::ResetSpiManager() { + g_spi_manager.reset(); +} + +bool SpiManager::RegisterSpiDevBus(const std::string& name, + uint32_t bus, + uint32_t cs) { + if (spidev_buses_.count(name)) + return false; + spidev_buses_.emplace(name, SpiDevBus(bus, cs)); + return true; +} + +std::vector<std::string> SpiManager::GetSpiDevBuses() { + std::vector<std::string> buses; + for (auto& i : spidev_buses_) + buses.push_back(i.first); + return buses; +} + +bool SpiManager::HasSpiDevBus(const std::string& name) { + return spidev_buses_.count(name); +} + +bool SpiManager::RegisterDriver( + std::unique_ptr<SpiDriverInfoBase> driver_info) { + std::string key = driver_info->Compat(); + driver_infos_[key] = std::move(driver_info); + return true; +} + +bool SpiManager::SetPinMux(const std::string& name, const std::string& mux) { + auto bus_it = spidev_buses_.find(name); + if (bus_it == spidev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = mux; + return true; +} + +bool SpiManager::SetPinMuxWithGroup(const std::string& name, + const std::string& mux, + const std::string& group) { + auto bus_it = spidev_buses_.find(name); + if (bus_it == spidev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = group; + return true; +} + +std::unique_ptr<SpiDevice> SpiManager::OpenSpiDevice(const std::string& name) { + // Get the Bus from the BSP. + auto bus_it = spidev_buses_.find(name); + if (bus_it == spidev_buses_.end()) + return nullptr; + + // Check its not alread in use + if (bus_it->second.driver_) { + return nullptr; + } + + // Find a driver. + // Currently there is only hardcoded support for SPIDEV + auto driver_info_it = driver_infos_.find("SPIDEV"); + + // Fail if there is no driver. + if (driver_info_it == driver_infos_.end()) + return nullptr; + + std::unique_ptr<SpiDriverInterface> driver(driver_info_it->second->Probe()); + + if (!driver->Init(bus_it->second.bus, bus_it->second.cs)) + return nullptr; + + // Set Pin muxing. + if (!bus_it->second.mux.empty()) { + PinMuxManager::GetPinMuxManager()->SetSource(bus_it->second.mux, + bus_it->second.mux_group); + } + + bus_it->second.driver_ = std::move(driver); + + return std::unique_ptr<SpiDevice>(new SpiDevice(&(bus_it->second))); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/spi_manager.h b/peripheralmanager/daemon/spi_manager.h new file mode 100644 index 0000000..9ef51e3 --- /dev/null +++ b/peripheralmanager/daemon/spi_manager.h
@@ -0,0 +1,126 @@ +/* + * 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_SPI_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" +#include "pin_mux_manager.h" +#include "spi_driver.h" + +namespace android { + +struct SpiDevBus { + SpiDevBus(uint32_t b, uint32_t c) : bus(b), cs(c) {} + uint32_t bus; + uint32_t cs; + std::string mux; + std::string mux_group; + std::unique_ptr<SpiDriverInterface> driver_; +}; + +class SpiDevice { + public: + explicit SpiDevice(SpiDevBus* bus) : bus_(bus) {} + ~SpiDevice() { + if (!bus_->mux.empty()) { + PinMuxManager::GetPinMuxManager()->ReleaseSource(bus_->mux, + bus_->mux_group); + } + bus_->driver_.reset(); + } + + bool WriteByte(uint8_t val) { return Transfer(&val, nullptr, sizeof(val)); } + + bool WriteBuffer(const void* data, size_t len) { + return Transfer(data, nullptr, len); + } + + bool Transfer(const void* tx_data, void* rx_data, size_t len) { + return bus_->driver_->Transfer(tx_data, rx_data, len); + } + + bool SetFrequency(uint32_t speed_hz) { + return bus_->driver_->SetFrequency(speed_hz); + } + + bool SetMode(SpiMode mode) { return bus_->driver_->SetMode(mode); } + + bool SetBitJustification(bool lsb_first) { + return bus_->driver_->SetBitJustification(lsb_first); + } + + bool SetBitsPerWord(uint8_t bits_per_word) { + return bus_->driver_->SetBitsPerWord(bits_per_word); + } + + bool SetDelay(uint16_t delay_usecs) { + return bus_->driver_->SetDelay(delay_usecs); + } + + private: + SpiDevBus* bus_; +}; + +class SpiManager { + public: + friend class SpiManagerTest; + ~SpiManager(); + + // Get the singleton. + static SpiManager* GetSpiManager(); + + // Reset the Spi manager. + static void ResetSpiManager(); + + // Used by the BSP to tell PMan of an SPI bus + // that can be used by a PMan client. + // Will return false if the bus has already been registered. + bool RegisterSpiDevBus(const std::string& name, uint32_t bus, uint32_t cs); + + std::vector<std::string> GetSpiDevBuses(); + bool HasSpiDevBus(const std::string& name); + + bool SetPinMux(const std::string& name, const std::string& mux); + bool SetPinMuxWithGroup(const std::string& name, + const std::string& mux, + const std::string& group); + + bool RegisterDriver(std::unique_ptr<SpiDriverInfoBase> driver_info); + + std::unique_ptr<SpiDevice> OpenSpiDevice(const std::string& name); + + private: + SpiManager(); + + std::map<std::string, std::unique_ptr<SpiDriverInfoBase>> driver_infos_; + std::map<std::string, SpiDevBus> spidev_buses_; + + DISALLOW_COPY_AND_ASSIGN(SpiManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_MANAGER_H_
diff --git a/peripheralmanager/daemon/spi_manager_unittest.cc b/peripheralmanager/daemon/spi_manager_unittest.cc new file mode 100644 index 0000000..924b014 --- /dev/null +++ b/peripheralmanager/daemon/spi_manager_unittest.cc
@@ -0,0 +1,67 @@ +/* + * 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 <stdio.h> + +#include <gtest/gtest.h> + +#include "fake_devices.h" +#include "spi_manager.h" +#include "spi_driver_spidev.h" + +namespace android { + +class SpiManagerTest : public ::testing::Test { + public: + SpiManagerTest() { + manager.RegisterDriver(std::unique_ptr<SpiDriverInfoBase>( + new SpiDriverInfo<SpiDriverSpiDev, CharDeviceFactory*>( + &device_factory))); + } + ~SpiManagerTest() = default; + + protected: + FakeDeviceFactory device_factory; + SpiManager manager; +}; + +TEST_F(SpiManagerTest, SimpleRegister) { + manager.RegisterSpiDevBus("SPI0_1", 0, 1); + std::vector<std::string> busses = manager.GetSpiDevBuses(); + ASSERT_EQ(1U, busses.size()); + ASSERT_EQ("SPI0_1", busses[0]); +} + +TEST_F(SpiManagerTest, SimpleOpen) { + manager.RegisterSpiDevBus("SPI0_1", 0, 1); + std::unique_ptr<SpiDevice> device(manager.OpenSpiDevice("SPI0_1")); + ASSERT_NE(nullptr, device); + std::unique_ptr<SpiDevice> device2(manager.OpenSpiDevice("SPI0_1")); + ASSERT_EQ(nullptr, device2); + device.reset(); + std::unique_ptr<SpiDevice> device3(manager.OpenSpiDevice("SPI0_1")); + ASSERT_NE(nullptr, device3); +} + +TEST_F(SpiManagerTest, SetFrequency) { + manager.RegisterSpiDevBus("SPI0_1", 0, 1); + std::unique_ptr<SpiDevice> device(manager.OpenSpiDevice("SPI0_1")); + ASSERT_NE(nullptr, device); + + device->SetFrequency(100); +} + +} // namespace android
diff --git a/peripheralmanager/daemon/uart_driver.h b/peripheralmanager/daemon/uart_driver.h new file mode 100644 index 0000000..e8d7ed7 --- /dev/null +++ b/peripheralmanager/daemon/uart_driver.h
@@ -0,0 +1,73 @@ +/* + * 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 <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: + explicit 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/peripheralmanager/daemon/uart_driver_sysfs.cc b/peripheralmanager/daemon/uart_driver_sysfs.cc new file mode 100644 index 0000000..41e3064 --- /dev/null +++ b/peripheralmanager/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/peripheralmanager/daemon/uart_driver_sysfs.h b/peripheralmanager/daemon/uart_driver_sysfs.h new file mode 100644 index 0000000..35085b7 --- /dev/null +++ b/peripheralmanager/daemon/uart_driver_sysfs.h
@@ -0,0 +1,58 @@ +/* + * 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 <base/macros.h> + +#include "char_device.h" +#include "uart_driver.h" + +namespace android { + +class UartDriverSysfs : public UartDriverInterface { + public: + explicit 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/peripheralmanager/daemon/uart_manager.cc b/peripheralmanager/daemon/uart_manager.cc new file mode 100644 index 0000000..bc98111 --- /dev/null +++ b/peripheralmanager/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/peripheralmanager/daemon/uart_manager.h b/peripheralmanager/daemon/uart_manager.h new file mode 100644 index 0000000..ba8fa51 --- /dev/null +++ b/peripheralmanager/daemon/uart_manager.h
@@ -0,0 +1,92 @@ +/* + * 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 <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: + explicit 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/peripheralmanager/example/Android.mk b/peripheralmanager/example/Android.mk new file mode 100644 index 0000000..a4099fb --- /dev/null +++ b/peripheralmanager/example/Android.mk
@@ -0,0 +1,147 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +# Flips a GPIO on and off. +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := peripheralman_gpio_flip +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + gpio_flip_example.cc \ + +include $(BUILD_EXECUTABLE) + +# Watches the state of a gpio with interrupts. +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := peripheralman_gpio_interrupt +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + gpio_interrupt_example.cc \ + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_flash_apa10c +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_flash_apa10c.cc \ + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := peripheralman_blink_led +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + led_example.cc \ + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_mcp9808 +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_mcp9808.cc \ + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_gy521 +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_gy521.cc \ + +include $(BUILD_EXECUTABLE) + +# Check that headers are C89 compatible. +include $(CLEAR_VARS) +LOCAL_MODULE := compatibility_test +LOCAL_CFLAGS := -Wall -Wextra -std=c89 -pedantic -Wmissing-prototypes \ + -Wstrict-prototypes -Wold-style-definition -Wno-comment + +LOCAL_SHARED_LIBRARIES := libperipheralman +LOCAL_STATIC_LIBRARIES := peripheral_manager_hal_headers + +LOCAL_SRC_FILES := headers_are_c89.c +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_uart +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_uart.cc \ + +include $(BUILD_EXECUTABLE)
diff --git a/peripheralmanager/example/gpio_flip_example.cc b/peripheralmanager/example/gpio_flip_example.cc new file mode 100644 index 0000000..6c6b267 --- /dev/null +++ b/peripheralmanager/example/gpio_flip_example.cc
@@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 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 <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + DEFINE_string(pin, "", "Pin to toggle"); + brillo::FlagHelper::Init(argc, argv, "Example PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + std::string pin_name = "IO13"; + if (!FLAGS_pin.empty()) + pin_name = FLAGS_pin; + + LOG(INFO) << "Toggling Pin " << pin_name; + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open GPIO pin. + BGpio* my_gpio; + int ret = + BPeripheralManagerClient_openGpio(client, pin_name.c_str(), &my_gpio); + if (ret) { + LOG(ERROR) << "Failed to open Gpio: " << strerror(ret); + return 1; + } + + // Set the direction to out. + ret = BGpio_setDirection(my_gpio, DIRECTION_OUT_INITIALLY_HIGH); + if (ret) { + LOG(ERROR) << "Failed to set gpio pin direction: " << strerror(ret); + return 1; + } + + // Toggle the output. + BGpio_setValue(my_gpio, 0); + sleep(1); + BGpio_setValue(my_gpio, 1); + + // Release the gpio pin + BGpio_delete(my_gpio); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +}
diff --git a/peripheralmanager/example/gpio_interrupt_example.cc b/peripheralmanager/example/gpio_interrupt_example.cc new file mode 100644 index 0000000..3261f81 --- /dev/null +++ b/peripheralmanager/example/gpio_interrupt_example.cc
@@ -0,0 +1,108 @@ +/* + * 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 <poll.h> +#include <sys/select.h> +#include <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + DEFINE_string(pin, "", "Pin to watch"); + DEFINE_bool(select, false, "Use select instead of poll"); + brillo::FlagHelper::Init(argc, argv, "Watches a GPIO."); + logging::InitLogging(logging::LoggingSettings()); + + std::string pin_name = "IO1"; + if (!FLAGS_pin.empty()) + pin_name = FLAGS_pin; + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open GPIO pin. + BGpio* my_gpio; + if (BPeripheralManagerClient_openGpio(client, pin_name.c_str(), &my_gpio)) { + LOG(ERROR) << "Failed to open Gpio"; + return 1; + } + + // Set the direction to in. + if (BGpio_setDirection(my_gpio, DIRECTION_IN)) { + LOG(ERROR) << "Failed to set gpio pin direction"; + return 1; + } + + // Set the edge trigger type for interrupts. + if (BGpio_setEdgeTriggerType(my_gpio, BOTH_EDGE)) { + LOG(ERROR) << "failed to set the edge type"; + return 1; + } + + // Get the file descriptor used to poll for data. + int fd = -1; + if (BGpio_getPollingFd(my_gpio, &fd)) { + LOG(ERROR) << "failed to get the fd"; + return 1; + } + + if (FLAGS_select) { + fd_set ifds; + FD_ZERO(&ifds); + FD_SET(fd, &ifds); + + for (int i = 0; i < 30; i++) { + select(fd + 1, NULL, NULL, &ifds, NULL); + LOG(INFO) << "received event"; + BGpio_ackInterruptEvent(fd); + } + } else { + struct pollfd poller = { + .fd = fd, + .events = POLLPRI | POLLERR, + .revents = 0, + }; + + for (int i = 0; i < 30; i++) { + // Poll with no timeout. + poll(&poller, 1, -1); + LOG(INFO) << "received an event "; + BGpio_ackInterruptEvent(fd); + poller.revents = 0; + } + } + + close(fd); + + // Release the gpio pin + BGpio_delete(my_gpio); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +}
diff --git a/peripheralmanager/example/headers_are_c89.c b/peripheralmanager/example/headers_are_c89.c new file mode 100644 index 0000000..ff13b4d --- /dev/null +++ b/peripheralmanager/example/headers_are_c89.c
@@ -0,0 +1,18 @@ +/* + * 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 "hardware/peripheral_io.h" +#include "peripheralmanager/peripheral_manager_client.h"
diff --git a/peripheralmanager/example/led_example.cc b/peripheralmanager/example/led_example.cc new file mode 100644 index 0000000..ab5c7b3 --- /dev/null +++ b/peripheralmanager/example/led_example.cc
@@ -0,0 +1,95 @@ +/* + * 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 <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + DEFINE_string(led, "", "Led to toggle"); + brillo::FlagHelper::Init(argc, argv, "Example client blinking a light."); + logging::InitLogging(logging::LoggingSettings()); + + if (FLAGS_led.empty()) { + LOG(ERROR) << "Led name not specified."; + return 1; + } + + LOG(INFO) << "Blinking " << FLAGS_led; + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open the LED. + BLed* led; + int ret = BPeripheralManagerClient_openLed(client, FLAGS_led.c_str(), &led); + if (ret) { + LOG(ERROR) << "Failed to open LED: " << strerror(ret); + return 1; + } + + uint32_t max_brightness = 0; + + // Get the maximum brightness possible. + ret = BLed_getMaxBrightness(led, &max_brightness); + if (ret) { + LOG(ERROR) << "Failed to get the maximum brightness: " << strerror(ret); + return 1; + } + + // Toggle the output. + BLed_setBrightness(led, 0); + sleep(1); + BLed_setBrightness(led, max_brightness / 2); + sleep(1); + BLed_setBrightness(led, max_brightness); + sleep(1); + BLed_setBrightness(led, max_brightness / 2); + sleep(1); + BLed_setBrightness(led, 0); + + // Make sure the led is turned off. + uint32_t brightness; + ret = BLed_getBrightness(led, &brightness); + if (ret) { + LOG(ERROR) << "Failed to read the brightness: " << strerror(ret); + return 1; + } + + if (brightness != 0) { + LOG(ERROR) << "Failed to turn the LED off, led is at: " + << std::to_string(brightness); + } + + // Release the LED + BLed_delete(led); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +}
diff --git a/peripheralmanager/example/pio_flash_apa10c.cc b/peripheralmanager/example/pio_flash_apa10c.cc new file mode 100644 index 0000000..82dfa33 --- /dev/null +++ b/peripheralmanager/example/pio_flash_apa10c.cc
@@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 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 <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +void SetLed(const BSpiDevice* my_spi, uint8_t r, uint8_t g, uint8_t b) { + uint8_t start_frame[] = {0x00, 0x00, 0x00, 0x00}; + uint8_t on_frame[4] = {0xff, 0x00, 0x00, 0x00}; + uint8_t end_frame[] = {0xff, 0xff, 0xff, 0xff}; + on_frame[1] = b; + on_frame[2] = g; + on_frame[3] = r; + BSpiDevice_writeBuffer(my_spi, start_frame, sizeof(start_frame)); + BSpiDevice_writeBuffer(my_spi, on_frame, sizeof(on_frame)); + BSpiDevice_writeBuffer(my_spi, end_frame, sizeof(end_frame)); +} + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + LOG(INFO) << "PeripheralManager Client"; + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open SPI bus. + BSpiDevice* my_spi; + int ret = BPeripheralManagerClient_openSpiDevice(client, "SPI2", &my_spi); + if (ret) { + LOG(ERROR) << "Failed to open Spi: " << strerror(ret); + return 1; + } + + BSpiDevice_setFrequency(my_spi, 400000); + + SetLed(my_spi, 0xff, 0x0, 0x0); + sleep(1); + SetLed(my_spi, 0x00, 0xff, 0x0); + sleep(1); + SetLed(my_spi, 0x00, 0x0, 0xff); + sleep(1); + + BSpiDevice_delete(my_spi); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +}
diff --git a/peripheralmanager/example/pio_gy521.cc b/peripheralmanager/example/pio_gy521.cc new file mode 100644 index 0000000..ec9296f --- /dev/null +++ b/peripheralmanager/example/pio_gy521.cc
@@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 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 <arpa/inet.h> +#include <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int16_t swap_bytes(int16_t i) { + return ((i & 0x00FF) << 8) + ((i & 0xFF00) >> 8); +} + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager example."); + logging::InitLogging(logging::LoggingSettings()); + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open I2C device. + BI2cDevice* i2c_device; + int ret = + BPeripheralManagerClient_openI2cDevice(client, "I2C6", 0x68, &i2c_device); + if (ret) { + LOG(ERROR) << "Failed to open I2C: " << strerror(ret); + return 1; + } + + // Turn the sensor on. + ret = BI2cDevice_writeRegByte(i2c_device, 0x6B, 0); + if (ret) { + LOG(ERROR) << "Failed to setup the device: " << strerror(ret); + return 1; + } + + // Read the "who am I" register (contains the device address). + uint8_t address; + ret = BI2cDevice_readRegByte(i2c_device, 0x75, &address); + if (ret) { + LOG(ERROR) << "Failed to read the WHO AM I register: " << strerror(ret); + return 1; + } + printf("I am at address is: 0x%X\n", address); + + int16_t temp = 0; + ret = BI2cDevice_readRegWord( + i2c_device, 0x41, reinterpret_cast<uint16_t*>(&temp)); + if (ret) { + LOG(ERROR) << "Failed to read the temp: " << strerror(ret); + return 1; + } + temp = ntohs(temp); + float t = temp; + printf("temp is: %.02f degrees Celsius.\n", t / 340 + 36.53); + + for (int j = 0; j < 50; j++) { + + // Read the values of the accelerometer. + int16_t accel_data[3]; + + uint32_t read; + ret = BI2cDevice_readRegBuffer(i2c_device, 0x3B, &accel_data, 6, &read); + if (ret || read != 6) { + LOG(ERROR) << "Failed to read the buffer: " << strerror(ret); + return 1; + } + + printf("Accelerometer values: X=%i, Y=%i, Z=%i\n", + swap_bytes(accel_data[0]), + swap_bytes(accel_data[1]), + swap_bytes(accel_data[2])); + + sleep(1); + } + + BI2cDevice_delete(i2c_device); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + return 0; +}
diff --git a/peripheralmanager/example/pio_mcp9808.cc b/peripheralmanager/example/pio_mcp9808.cc new file mode 100644 index 0000000..446afbf --- /dev/null +++ b/peripheralmanager/example/pio_mcp9808.cc
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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 <arpa/inet.h> +#include <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open I2C bus. + BI2cDevice* i2c_device; + int ret = + BPeripheralManagerClient_openI2cDevice(client, "I2C6", 0x18, &i2c_device); + if (ret) { + LOG(ERROR) << "Failed to open I2C: " << strerror(ret); + return 1; + } + + uint16_t val = 0; + BI2cDevice_readRegWord(i2c_device, 0x05, &val); + + val = ntohs(val); + float temp = (val >> 4) & 0xFF; + temp += (float)(val & 0xF) / 16; + printf("Temp: %f\n", temp); + + BI2cDevice_delete(i2c_device); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + return 0; +}
diff --git a/peripheralmanager/example/pio_uart.cc b/peripheralmanager/example/pio_uart.cc new file mode 100644 index 0000000..628a746 --- /dev/null +++ b/peripheralmanager/example/pio_uart.cc
@@ -0,0 +1,89 @@ +/* + * 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 <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + BUartDevice* uart; + int ret = BPeripheralManagerClient_openUartDevice(client, "UART1", &uart); + if (ret) { + LOG(ERROR) << "Failed to open UART device"; + return 1; + } + + ret = BUartDevice_setBaudrate(uart, 9600); + + char greeting[] = "What is your name ?\n"; + uint32_t written = 0; + ret = BUartDevice_write(uart, greeting, strlen(greeting), &written); + if (ret) { + LOG(ERROR) << "failed to write: " << strerror(ret); + return 1; + } + + std::string name = ""; + + while (name.size() < 40) { + // If the user entered a newline, everything before is the name. + auto first_newline = name.find(13); + if (first_newline != std::string::npos) { + name.resize(first_newline); + break; + } + + char buffer[40]; + uint32_t bytes_read = 0; + + // Read some data. + ret = BUartDevice_read(uart, buffer, 40, &bytes_read); + if (ret != 0 && ret != EAGAIN) { + LOG(ERROR) << "failed to read: " << strerror(ret); + return 1; + } + LOG(INFO) << "read " << bytes_read << "bytes"; + name.append(buffer, bytes_read); + + // Wait a little before reading again. + // This should be replaced by a more efficient polling mechanism when it is + // ready. + sleep(2); + } + + LOG(INFO) << "hello " << name; + + // Release the UART object. + BUartDevice_delete(uart); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +}
diff --git a/peripheralmanager/hal/Android.mk b/peripheralmanager/hal/Android.mk new file mode 100644 index 0000000..9e0d4e1 --- /dev/null +++ b/peripheralmanager/hal/Android.mk
@@ -0,0 +1,22 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := peripheral_manager_hal_headers +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +include $(BUILD_STATIC_LIBRARY)
diff --git a/peripheralmanager/hal/hardware/peripheral_io.h b/peripheralmanager/hal/hardware/peripheral_io.h new file mode 100644 index 0000000..624e83b --- /dev/null +++ b/peripheralmanager/hal/hardware/peripheral_io.h
@@ -0,0 +1,286 @@ +/* + * 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 ANDROID_PERIPHERAL_IO_INTERFACE_H +#define ANDROID_PERIPHERAL_IO_INTERFACE_H + +#include <stdint.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <hardware/hardware.h> + +__BEGIN_DECLS + +/** + * Id of this module. + */ +#define PERIPHERAL_IO_HARDWARE_MODULE_ID "peripheral_io" + +/** + * Possible GPIO direction configuration. + */ +typedef enum { + GPIO_DIRECTION_IN, /** Input */ + GPIO_DIRECTION_OUT_LOW, /** Output, initially low */ + GPIO_DIRECTION_OUT_HIGH /** Output, initially high */ +} gpio_direction_t; + +/** + * Callback to enable a given pinmux source on a specific pin. + * + * Args: + * pin: Name of the pin. + * source: Name of the pinmux source to enable. When NULL, setup the pinmux + * to enable GPIO on this pin. + * + * Returns: + * 0 on success, errno on error. + */ +typedef int (*pin_mux_cb)(const char* pin, const char* source); + +/** + * Callback to set the direction of a given GPIO. + * + * Args: + * pin: Name of the pin to configure. + * dir: Direction to set. One of gpio_direction_t. + * + * Returns: + * 0 on success, errno on error. + */ +typedef int (*pin_mux_direction_cb)(const char* pin, int dir); + +/** + * Callbacks used by peripheral manager to configure given pins. + */ +typedef struct pin_mux_callbacks { + pin_mux_cb mux_cb; + pin_mux_direction_cb direction_cb; +} pin_mux_callbacks; + +/** + * Callbacks into peripheral manager. + * + * Those callbacks must be used in register_devices to declare the available + * interfaces to peripheral manager. + * + * All peripherals are referred to by their friendly name. + * The friendly name is a string, used to refer to a given peripheral (ex: gpio + * name, spi bus name) that is simple to understand, well documented for the + * board and unambiguous. + * + * Before coming up with a new naming scheme, consider: + * - Using an existing naming scheme: if the board provides an arduino pinout, a + * raspberry Pi pinout or a 96 boards pinout, use it. + * - Using the names written on the board next to the physical ports if any. + * - Using the documented name when widely available. + * Referring to the same pin or peripheral by two different names in the + * documentation and in peripheral manager would be confusing to the user. + * + * If coming up with a new name, use only simple characters (ideally, A-Z, 0-9, + * -, _). + */ +typedef struct peripheral_registration_cb_t { + /** + * Register a pin. + * + * Args: + * name: Friendly name (see definition above) of the pin. + * callbacks: Callbacks used to set up pinmuxes. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_pin)(const char* name, int gpio, pin_mux_callbacks callbacks); + + /** + * Register a pin group. + * + * Args: + * name: Name of the group. + * pins: List of pin names that are part of the group. + * nr_pins: Size of |pins|. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_pin_group)(const char* name, char** pins, size_t nr_pins); + + /** + * Register a pinmux source. + * + * Args: + * name: Name of the pinmux source. + * groups: List of possible pinmux groups this source can come up on. + * nr_groups: Size of |groups|. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_source)(const char* name, char** groups, size_t nr_groups); + + /** + * Register a simple source, mapped to a single pin group. + * + * This convenience function replaces the two calls to register_pin_group and + * register_source in most cases. + * + * Args: + * name: Name of the pinmux source. + * pins: List of pins this source comes up on. + * nr_pins: Size of |pins|. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_simple_source)(const char* name, + const char** pins, + size_t nr_pins); + + /** + * Register a sysfs backed GPIO. + * + * Args: + * name: Friendly name of the GPIO. + * index: Index of the gpio in sysfs. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_gpio_sysfs)(const char* name, uint32_t index); + + /** + * Set the pinmux for a given GPIO. + * + * Args: + * name: Friendly name of the pin. + * source: Name of the pinmux source. + * + * Returns: + * 0 on success, errno on error. + */ + int (*set_gpio_pin_mux)(const char* name, const char* source); + + /** + * Register a SPI device. + * + * Args: + * name: Friendly name of the device. + * bus: Bus number. + * cs: Chip select. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_spi_dev_bus)(const char* name, uint32_t bus, uint32_t cs); + + /** + * Set the pinmux for a given SPI device. + * + * Args: + * name: Friendly name of the device. + * source: Name of the pinmuxing source. + * + * Returns: + * 0 on success, errno on error. + */ + int (*set_spi_pin_mux)(const char* name, const char* source); + + /** + * Register a sysfs-backed LED. + * + * Args: + * name: Friendly name of the LED. + * sysfs_name: Name of the device in sysfs. + * + * Returns: + * 0 on success, errno on error. + */ + 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: + * name: Friendly name of the I2C device. + * bus: I2C bus number. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_i2c_dev_bus)(const char* name, uint32_t bus); + + /** + * Set the pinmux for a given I2C bus. + * + * Args: + * name: Friendly name of the I2C bus. + * source: Name of the pinmuxing source. + * + * Returns: + * 0 on success, errno on error. + */ + int (*set_i2c_pin_mux)(const char* name, const char* source); + +} peripheral_registration_cb_t; + +typedef struct peripheral_io_module_t peripheral_io_module_t; + +struct peripheral_io_module_t { + struct hw_module_t common; + + /** + * Register all available devices with the peripheral manager. + * + * Arguments: + * dev: Pointer to the peripheral_io module. + * callbacks: Callbacks into peripheral manager to register devices. + * + * Returns: + * 0 on success, errno on error. + */ + int (*register_devices)(const peripheral_io_module_t* dev, + const peripheral_registration_cb_t* callbacks); +}; + +__END_DECLS + +#endif // ANDROID_PERIPHERAL_IO_INTERFACE_H
diff --git a/peripheralmanager/include/peripheralmanager/gpio.h b/peripheralmanager/include/peripheralmanager/gpio.h new file mode 100644 index 0000000..d55a0ae --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/gpio.h
@@ -0,0 +1,109 @@ +/* + * 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_GPIO_H_ +#define SYSTEM_PERIPHERALMANAGER_GPIO_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup Gpio Gpio Interface +/// @brief Functions to control gpio pins. +/// +/// These functions can be used to control gpio. +/// @{ + +/// Edge trigger types. +enum { + NONE_EDGE, /**< None */ + RISING_EDGE, /**< Rising edge */ + FALLING_EDGE, /**< Falling edge */ + BOTH_EDGE /**< Both edges */ +}; + +/// GPIO direction types. +enum { + DIRECTION_IN, /**< Input mode */ + DIRECTION_OUT_INITIALLY_HIGH, /**< Output mode, initially set to high */ + DIRECTION_OUT_INITIALLY_LOW /**< Output mode, initially set to low */ +}; + +/// Possible active types. +enum { + ACTIVE_LOW, /**< Active Low */ + ACTIVE_HIGH /**< Active High */ +}; + +typedef struct BGpio BGpio; + + + +/// Sets the GPIO direction to output. +/// @param gpio Pointer to the BGpio struct +/// @param direction One of DIRECTION_IN, +/// DIRECTION_OUT_INITIALLY_HIGH, DIRECTION_OUT_INITIALLY_LOW. +/// @return 0 on success, errno on error. +int BGpio_setDirection(const BGpio* gpio, int direction); + +/// Sets the interrupt edge trigger type. +/// @param gpio Pointer to the BGpio struct +/// @param type One of NONE_EDGE, RISING_EDGE, FALLING_EDGE or BOTH_EDGE. +/// @return 0 on success, errno on error. +int BGpio_setEdgeTriggerType(const BGpio* gpio, int type); + +/// Sets the GPIO’s active low/high status. +/// @param gpio Pointer to the BGpio struct. +/// @param type One of ACTIVE_HIGH, ACTIVE_LOW. +/// @return 0 on success, errno on error. +int BGpio_setActiveType(const BGpio* gpio, int type); + +/// Sets the GPIO value (for output GPIO only). +/// @param gpio Pointer to the BGpio struct. +/// @param value Value to set. +/// @return 0 on success, errno on error. +int BGpio_setValue(const BGpio* gpio, int value); + +/// Gets the GPIO value (for input GPIO only). +/// @param gpio Pointer to the BGpio struct. +/// @param value Output pointer to the value of the GPIO. +/// @return 0 on success, errno on error. +int BGpio_getValue(const BGpio* gpio, int* value); + +/// Returns a file descriptor that can be used to poll on new data. +/// Can be passed to select/epoll to wait for data to become available. +/// @param gpio Pointer to the BGpio struct. +/// @param fd Output pointer to the file descriptor number. +/// @return 0 on success, errno on error. +int BGpio_getPollingFd(const BGpio* gpio, int* fd); + +/// Acknowledges the interrupt and resets the file descriptor. +/// This must be called after each event triggers in order to be able to +/// poll/select for another event. +/// @param fd Polling file descriptor to reset. +/// @return 0 on success, errno on error. +int BGpio_ackInterruptEvent(int fd); + +/// Destroys a BGpio struct. +/// @param gpio Pointer to the BGpio struct. +void BGpio_delete(BGpio* gpio); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_GPIO_H_
diff --git a/peripheralmanager/include/peripheralmanager/i2c_device.h b/peripheralmanager/include/peripheralmanager/i2c_device.h new file mode 100644 index 0000000..ca14477 --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/i2c_device.h
@@ -0,0 +1,121 @@ +/* + * 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_I2C_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup I2c I2c device interface +/// @brief Functions to control an I2C device. +/// +/// These functions can be used to control an I2C device. +/// @{ + +typedef struct BI2cDevice BI2cDevice; + +/// Reads from the device. +/// @param device Pointer to the BI2cDevice struct. +/// @param data Output buffer to write the data to. +/// @param len Number of bytes to read. +/// @param bytes_read Output pointer to the number of bytes actually read. +/// @return 0 on success, errno on error +int BI2cDevice_read(const BI2cDevice* device, + void* data, + uint32_t len, + uint32_t* bytes_read); + +/// Reads a byte from an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to read from. +/// @param val Output pointer to value to read. +/// @return 0 on success, errno on error +int BI2cDevice_readRegByte(const BI2cDevice* device, uint8_t reg, uint8_t* val); + +/// Reads a word from an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to read from. +/// @param val Output pointer to value to read. +/// @return 0 on success, errno on error +int BI2cDevice_readRegWord(const BI2cDevice* device, + uint8_t reg, + uint16_t* val); + +/// Reads from an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to read from. +/// @param data Output buffer to write the data to. +/// @param len Number of bytes to read. +/// @param bytes_read Output pointer to the number of bytes read. +/// @return 0 on success, errno on error +int BI2cDevice_readRegBuffer(const BI2cDevice* device, + uint8_t reg, + void* data, + uint32_t len, + uint32_t* bytes_read); + +/// Writes to the device. +/// @param device Pointer to the BI2cDevice struct. +/// @param data Buffer to write. +/// @param len Number of bytes to write. +/// @param bytes_written Output pointer to the number of bytes written. +/// @return 0 on success, errno on error +int BI2cDevice_write(const BI2cDevice* device, + const void* data, + uint32_t len, + uint32_t* bytes_written); + +/// Writes a byte to an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to write to. +/// @param val Value to write. +/// @return 0 on success, errno on error +int BI2cDevice_writeRegByte(const BI2cDevice* device, uint8_t reg, uint8_t val); + +/// Writes a word to an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to write to. +/// @param val Value to write. +/// @return 0 on success, errno on error +int BI2cDevice_writeRegWord(const BI2cDevice* device, + uint8_t reg, + uint16_t val); + +/// Writes to an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param reg Register to write to. +/// @param data Data to write. +/// @param len Number of bytes to write. +/// @param bytes_written Output pointer to the number of bytes written. +/// @return 0 on success, errno on error +int BI2cDevice_writeRegBuffer(const BI2cDevice* device, + uint8_t reg, + const void* data, + uint32_t len, + uint32_t* bytes_written); + +/// Destroys a BI2cDevice struct. +/// @param device Pointer to the BI2cDevice struct. +void BI2cDevice_delete(BI2cDevice* device); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_H_
diff --git a/peripheralmanager/include/peripheralmanager/led.h b/peripheralmanager/include/peripheralmanager/led.h new file mode 100644 index 0000000..c8cc19b --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/led.h
@@ -0,0 +1,60 @@ +/* + * 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_LED_H_ +#define SYSTEM_PERIPHERALMANAGER_LED_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup Led Led Interface +/// @brief Functions to control onboard LEDs. +/// +/// These functions can be used to query and control LEDs. +/// @{ + +typedef struct BLed BLed; + +/// Sets the LED brightness. +/// @param led Pointer to the BLed object. +/// @param brightness Brightness to set. If the brightness exceeds the maximum +/// brightness supported, sets the maximum supported. +/// @return 0 on success, errno on error. +int BLed_setBrightness(const BLed* led, uint32_t brightness); + +/// Gets the LED brightness. +/// @param led Pointer to the BLed object. +/// @param brightness Output pointer to the current brightness. +/// @return 0 on success, errno on error. +int BLed_getBrightness(const BLed* led, uint32_t* brightness); + +/// Gets the LED max brightness. +/// @param led Pointer to the BLed object. +/// @param max_brightness Output pointer to the maximum brightness supported. +/// @return 0 on success, errno on error. +int BLed_getMaxBrightness(const BLed* led, uint32_t* max_brightness); + +/// Destroys a BLed object. +/// @param led Pointer to the BLed object to destroy. +void BLed_delete(BLed* led); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_LED_H_
diff --git a/peripheralmanager/include/peripheralmanager/peripheral_manager_client.h b/peripheralmanager/include/peripheralmanager/peripheral_manager_client.h new file mode 100644 index 0000000..51821b0 --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/peripheral_manager_client.h
@@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 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_PERIPHERAL_MANAGER_CLIENT_H_ +#define SYSTEM_PERIPHERALMANAGER_PERIPHERAL_MANAGER_CLIENT_H_ + +#include <sys/cdefs.h> + +#include "peripheralmanager/gpio.h" +#include "peripheralmanager/i2c_device.h" +#include "peripheralmanager/led.h" +#include "peripheralmanager/spi_device.h" +#include "peripheralmanager/uart_device.h" + +__BEGIN_DECLS + +/// @defgroup PeripheralManagerClient Peripheral client functions +/// @brief Functions to access embedded peripherals +/// @{ + +typedef struct BPeripheralManagerClient BPeripheralManagerClient; + +/// Returns the list of GPIOs. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_gpio Output pointer to the number of element in the list. +/// @return The list of gpios. +char** BPeripheralManagerClient_listGpio(const BPeripheralManagerClient* client, + int* num_gpio); + +/// Opens a GPIO and takes ownership of it. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the GPIO. +/// @param gpio Output pointer to the BGpio struct. Empty on error. +/// @return 0 on success, errno on error. +int BPeripheralManagerClient_openGpio(const BPeripheralManagerClient* client, + const char* name, + BGpio** gpio); + +/// Returns the list of SPI buses. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_spi_buses Output pointer to the number of element in the list. +/// @return The list of spi buses. +char** BPeripheralManagerClient_listSpiBuses( + const BPeripheralManagerClient* client, + int* num_spi_buses); + +/// Opens a SPI device and takes ownership of it. +/// @oaram client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the SPI device. +/// @param dev Output pointer to the BSpiDevice struct. Empty on error. +/// @return 0 on success, errno on error. +int BPeripheralManagerClient_openSpiDevice( + const BPeripheralManagerClient* client, + const char* name, + BSpiDevice** dev); + +/// Returns the list of LEDs available. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_leds Output pointer to the number of leds. +/// @return The list of LEDs. The list must be freed by the caller. +char** BPeripheralManagerClient_listLeds(const BPeripheralManagerClient* client, + int* num_leds); + +/// Opens an LED and takes ownership of it. +/// @oaram client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the LED. +/// @param dev Output pointer to the BLed struct. Empty on error. +/// @return 0 on success, errno on error. +int BPeripheralManagerClient_openLed(const BPeripheralManagerClient* client, + const char* name, + BLed** led); + +/// Returns the list of I2C buses. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_i2c_buses Output pointer to the number of element in the list. +/// @return The list of i2c buses. +char** BPeripheralManagerClient_listI2cBuses( + const BPeripheralManagerClient* client, + int* num_i2c_buses); + +/// Opens an I2C device and takes ownership of it. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the I2C bus. +/// @param address Address of the I2C device. +/// @param dev Output pointer to the BI2cDevice struct. Empty on error. +/// @return 0 on success, errno on error +int BPeripheralManagerClient_openI2cDevice( + const BPeripheralManagerClient* client, + const char* name, + uint32_t address, + BI2cDevice** dev); + +/// Returns the list of UART buses. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_uart_buses Output pointer to the number of element in the list. +/// @return The list of uart buses. +char** BPeripheralManagerClient_listUartDevices( + const BPeripheralManagerClient* client, int* num_uart_buses); + +/// Opens an UART device and takes ownership of it. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the UART device. +/// @param dev Output pointer to the BUartDevice struct. Empty on error. +/// @return 0 on success, errno on error +int BPeripheralManagerClient_openUartDevice( + const BPeripheralManagerClient* client, + const char* name, + BUartDevice** dev); + +/// Creates a new client. +/// @return A pointer to the created client. nullptr on errors. +BPeripheralManagerClient* BPeripheralManagerClient_new(); + +/// Destroys the peripheral manager client. +/// @param client Pointer to the BPeripheralManagerClient struct. +void BPeripheralManagerClient_delete(BPeripheralManagerClient* client); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_PERIPHERAL_MANAGER_CLIENT_H_
diff --git a/peripheralmanager/include/peripheralmanager/spi_device.h b/peripheralmanager/include/peripheralmanager/spi_device.h new file mode 100644 index 0000000..e81bdc1 --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/spi_device.h
@@ -0,0 +1,118 @@ +/* + * 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_SPI_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_SPI_DEVICE_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup Spi Spi device interface +/// @brief Functions to control an SPI device. +/// +/// These functions can be used to control an SPI device. +/// @{ + +/// Endianness. +enum { + SPI_LSB_FIRST, /**< Least significant bits first */ + SPI_MSB_FIRST /**< Most significant bits first */ +}; + +/// SPI phase modes. +enum { + SPI_CPHA = 0x01, /**< Clock phase */ + SPI_CPOL = 0x02 /**< Clock polarity */ +}; + +/// SPI modes (similar to the Linux kernel's modes). +enum { + SPI_MODE0 = 0, /**< CPHA=0, CPOL=0 */ + SPI_MODE1 = SPI_CPHA, /**< CPHA=1, CPOL=0 */ + SPI_MODE2 = SPI_CPOL, /**< CPHA=0, CPOL=1 */ + SPI_MODE3 = SPI_CPHA + SPI_CPOL /**< CPHA=1, CPOL=1 */ +}; + +typedef struct BSpiDevice BSpiDevice; + +/// Writes a byte to the device. +/// @param device Pointer to the BSpiDevice struct. +/// @param val Value to write. +/// @return 0 on success, errno on error. +int BSpiDevice_writeByte(const BSpiDevice* device, uint8_t val); + +/// Writes a buffer to the device. +/// @param device Pointer to the BSpiDevice struct. +/// @param data Buffer to write. +/// @param len Length of the buffer. +/// @return 0 on success, errno on error. +int BSpiDevice_writeBuffer(const BSpiDevice* device, + const void* data, + size_t len); + +/// Transfer data to the device. +/// @param device Pointer to the BSpiDevice struct. +/// @param tx_data Buffer to write. +/// @param rx_data Buffer to read data in. If NULL, no data will be read. +/// @param len Length of the buffers. +/// @return 0 on success, errno on error. +int BSpiDevice_transfer(const BSpiDevice* device, + const void* tx_data, + void* rx_data, + size_t len); + +/// Sets the frequency in Hertz. +/// @param device Pointer to the BSpiDevice struct. +/// @param freq_hz Frequency to set. +/// @return 0 on success, errno on error. +int BSpiDevice_setFrequency(const BSpiDevice* device, uint32_t freq_hz); + +/// Sets the SPI mode. +/// @param device Pointer to the BSpiDevice struct. +/// @param mode Mode to use. One of SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3. +/// @return 0 on success, errno on error. +int BSpiDevice_setMode(const BSpiDevice* device, int mode); + +/// Sets the bit justification. +/// @param device Pointer to the BSpiDevice struct. +/// @param bit_justification One of SPI_LSB_FIRST OR SPI_MSB_FIRST. +/// @return 0 on success, errno on error. +int BSpiDevice_setBitJustification(const BSpiDevice* device, + int bit_justification); + +/// Sets the number of bits per words. +/// @param device Pointer to the BSpiDevice struct. +/// @param bits_per_word Number of bits per word. +/// @return 0 on success, errno on error. +int BSpiDevice_setBitsPerWord(const BSpiDevice* device, uint8_t bits_per_word); + +/// Sets the delay to wait after each transfer. +/// @param device Pointer to the BSpiDevice struct. +/// @param delay_usecs Delay in microseconds. +/// @return 0 on success, errno on error. +int BSpiDevice_setDelay(const BSpiDevice* device, uint16_t delay_usecs); + +/// Destroys a BSpiDevice struct. +/// @param device Pointer to the BSpiDevice struct. +void BSpiDevice_delete(BSpiDevice* device); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_SPI_DEVICE_H_
diff --git a/peripheralmanager/include/peripheralmanager/uart_device.h b/peripheralmanager/include/peripheralmanager/uart_device.h new file mode 100644 index 0000000..057a068 --- /dev/null +++ b/peripheralmanager/include/peripheralmanager/uart_device.h
@@ -0,0 +1,70 @@ +/* + * 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_UART_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_UART_DEVICE_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup Uart Uart device interface +/// @brief Functions to control an UART device. +/// +/// These functions can be used to control an UART device. +/// @{ + +typedef struct BUartDevice BUartDevice; + +/// Writes to a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param data Data to write. +/// @param len Size of the data to write. +/// @param bytes_written Output pointer to the number of bytes written. +/// @return 0 on success, errno on error. +int BUartDevice_write(const BUartDevice* device, + const void* data, + uint32_t len, + uint32_t* bytes_written); + +/// Reads from a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param data Buffer to read the data into. +/// @param len Number of bytes to read. +/// @param bytes_read Output pointer to the number of bytes read. +/// @return 0 on success, errno on error. +int BUartDevice_read(const BUartDevice* device, + void* data, + uint32_t len, + uint32_t* bytes_read); + +/// Sets the input and output speed of a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param device Uart device to configure. +/// @param baudrate Speed in baud. +/// @return 0 on success, errno on error. +int BUartDevice_setBaudrate(const BUartDevice* device, uint32_t baudrate); + +/// Destroys a BUartDevice struct. +/// @param device Pointer to the BUartDevice struct. +void BUartDevice_delete(BUartDevice* device); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_UART_DEVICE_H_
diff --git a/peripheralmanager/ipc/Android.mk b/peripheralmanager/ipc/Android.mk new file mode 100644 index 0000000..1d132fe --- /dev/null +++ b/peripheralmanager/ipc/Android.mk
@@ -0,0 +1,33 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libperipheralman_binder + +LOCAL_SHARED_LIBRARIES := libbinder +LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder + +LOCAL_SRC_FILES := \ + android/os/IPeripheralManagerClient.aidl \ + android/os/IPeripheralManager.aidl \ + +LOCAL_SHARED_LIBRARIES := libbinder + +LOCAL_AIDL_INCLUDES := $(LOCAL_PATH) + +include $(BUILD_STATIC_LIBRARY)
diff --git a/peripheralmanager/ipc/android/os/IPeripheralManager.aidl b/peripheralmanager/ipc/android/os/IPeripheralManager.aidl new file mode 100644 index 0000000..39f4c9b --- /dev/null +++ b/peripheralmanager/ipc/android/os/IPeripheralManager.aidl
@@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 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. + */ + +package android.os; + +import android.os.IPeripheralManagerClient; + +interface IPeripheralManager { + IPeripheralManagerClient GetClient(IBinder lifeline); +}
diff --git a/peripheralmanager/ipc/android/os/IPeripheralManagerClient.aidl b/peripheralmanager/ipc/android/os/IPeripheralManagerClient.aidl new file mode 100644 index 0000000..98e1196 --- /dev/null +++ b/peripheralmanager/ipc/android/os/IPeripheralManagerClient.aidl
@@ -0,0 +1,117 @@ +/* + * 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. + */ + +package android.os; + +interface IPeripheralManagerClient { + // Gpio functions. + void ListGpio(out @utf8InCpp List<String> gpios); + + void OpenGpio(@utf8InCpp String name); + + void ReleaseGpio(@utf8InCpp String name); + + void SetGpioEdge(@utf8InCpp String name, int type); + + void SetGpioActiveType(@utf8InCpp String name, int type); + + void SetGpioDirection(@utf8InCpp String name, int direction); + + void SetGpioValue(@utf8InCpp String name, boolean value); + + boolean GetGpioValue(@utf8InCpp String name); + + FileDescriptor GetGpioPollingFd(@utf8InCpp String name); + + + // Spi functions. + void ListSpiBuses(out @utf8InCpp List<String> buses); + + void OpenSpiDevice(@utf8InCpp String name); + + void ReleaseSpiDevice(@utf8InCpp String name); + + void SpiDeviceWriteByte(@utf8InCpp String name, byte data); + + void SpiDeviceWriteBuffer(@utf8InCpp String name, in byte[] buffer); + + void SpiDeviceTransfer(@utf8InCpp String name, in @nullable byte[] tx_data, + out @nullable byte[] rx_data, int len); + + void SpiDeviceSetFrequency(@utf8InCpp String name, int frequency_hz); + + void SpiDeviceSetBitJustification(@utf8InCpp String name, + boolean lsb_first); + + void SpiDeviceSetMode(@utf8InCpp String name, int mode); + + void SpiDeviceSetBitsPerWord(@utf8InCpp String name, int nbits); + + void SpiDeviceSetDelay(@utf8InCpp String name, int delay_usecs); + + + // Leds functions. + void ListLeds(out @utf8InCpp List<String> leds); + + void OpenLed(@utf8InCpp String name); + + void ReleaseLed(@utf8InCpp String name); + + int LedGetBrightness(@utf8InCpp String name); + + int LedGetMaxBrightness(@utf8InCpp String name); + + void LedSetBrightness(@utf8InCpp String name, int brightness); + + + // I2c functions. + void ListI2cBuses(out @utf8InCpp List<String> buses); + + void OpenI2cDevice(@utf8InCpp String name, int address); + + void ReleaseI2cDevice(@utf8InCpp String name, int address); + + int I2cRead(@utf8InCpp String name, int address, out byte[] data, int size); + + int I2cReadRegByte(@utf8InCpp String name, int address, int reg); + + int I2cReadRegWord(@utf8InCpp String name, int address, int reg); + + int I2cReadRegBuffer(@utf8InCpp String name, int address, int reg, + out byte[] data, int size); + + int I2cWrite(@utf8InCpp String name, int address, in byte[] data); + + void I2cWriteRegByte(@utf8InCpp String name, int address, int reg, byte val); + + void I2cWriteRegWord(@utf8InCpp String name, int address, int reg, int val); + + int I2cWriteRegBuffer(@utf8InCpp String name, int address, int reg, + in byte[] data); + + // Uart functions + void ListUartDevices(out @utf8InCpp List<String> devices); + + void OpenUartDevice(@utf8InCpp String name); + + void ReleaseUartDevice(@utf8InCpp String name); + + void SetUartDeviceBaudrate(@utf8InCpp String name, int baudrate); + + int UartDeviceWrite(@utf8InCpp String name, in byte[] data); + + int UartDeviceRead(@utf8InCpp String name, out byte[] data, int size); +}