From 6393c2294526d60995c1f87b22f469fdbf717035 Mon Sep 17 00:00:00 2001 From: "wansu.yoo" Date: Fri, 17 Jun 2016 18:07:51 +0900 Subject: [PATCH 02/11] Initial update for artik device-manager-plugin Change-Id: I42640d91a5509f755cdd99a1ab4f5ad55cc22573 Signed-off-by: wansu.yoo --- CMakeLists.txt | 9 + LICENSE | 202 ++++++++++++++++ hw/battery/CMakeLists.txt | 19 ++ hw/battery/battery.c | 308 +++++++++++++++++++++++++ hw/display/CMakeLists.txt | 19 ++ hw/display/display.c | 147 ++++++++++++ hw/external_connection/CMakeLists.txt | 19 ++ hw/external_connection/external_connection.c | 216 +++++++++++++++++ hw/shared.c | 129 +++++++++++ hw/shared.h | 43 ++++ hw/touchscreen/CMakeLists.txt | 19 ++ hw/touchscreen/touchscreen.c | 178 ++++++++++++++ hw/udev.c | 298 ++++++++++++++++++++++++ hw/udev.h | 43 ++++ packaging/device-manager-plugin-artik.manifest | 5 + packaging/device-manager-plugin-artik.spec | 42 ++++ 16 files changed, 1696 insertions(+) create mode 100755 CMakeLists.txt create mode 100755 LICENSE create mode 100755 hw/battery/CMakeLists.txt create mode 100755 hw/battery/battery.c create mode 100755 hw/display/CMakeLists.txt create mode 100755 hw/display/display.c create mode 100755 hw/external_connection/CMakeLists.txt create mode 100755 hw/external_connection/external_connection.c create mode 100755 hw/shared.c create mode 100755 hw/shared.h create mode 100755 hw/touchscreen/CMakeLists.txt create mode 100755 hw/touchscreen/touchscreen.c create mode 100755 hw/udev.c create mode 100755 hw/udev.h create mode 100755 packaging/device-manager-plugin-artik.manifest create mode 100755 packaging/device-manager-plugin-artik.spec diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..0414f0c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(device-manager-exynos3250 C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +ADD_SUBDIRECTORY(hw/battery) +ADD_SUBDIRECTORY(hw/display) +ADD_SUBDIRECTORY(hw/external_connection) +ADD_SUBDIRECTORY(hw/touchscreen) diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..fef8c29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/hw/battery/CMakeLists.txt b/hw/battery/CMakeLists.txt new file mode 100755 index 0000000..9703427 --- /dev/null +++ b/hw/battery/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(battery C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(battery_pkgs REQUIRED hwcommon dlog glib-2.0) + +FOREACH(flag ${battery_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE battery.c ../shared.c ../udev.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${battery_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/battery/battery.c b/hw/battery/battery.c new file mode 100755 index 0000000..0ff4fc9 --- /dev/null +++ b/hw/battery/battery.c @@ -0,0 +1,308 @@ +/* + * device-node + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "../shared.h" +#include "../udev.h" + +#define BATTERY_ROOT_PATH "/sys/class/power_supply" + +static struct uevent_data { + BatteryUpdated updated_cb; + void *data; +} udata = { 0, }; + +static int get_power_source(char **src) +{ + int ret, val; + + if (!src) + return -EINVAL; + + ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_AC"/online", &val); + if (ret >= 0 && val > 0) { + *src = POWER_SOURCE_AC; + return 0; + } + + ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_USB"/online", &val); + if (ret >= 0 && val > 0) { + *src = POWER_SOURCE_USB; + return 0; + } + + ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_WIRELESS"/online", &val); + if (ret >= 0 && val > 0) { + *src = POWER_SOURCE_WIRELESS; + return 0; + } + + *src = POWER_SOURCE_NONE; + + return 0; +} + +static void remove_not_string(char *str) +{ + char *t = str; + + while(*t != '\0') { + if (*t == '\r' || + *t == '\n' || + *t == '\x0a') + *t = '\0'; + else + t++; + } +} + +static void uevent_delivered(struct udev_device *dev) +{ + struct battery_info info; + char *val; + int ret; + + _I("POWER_SUPPLY uevent is delivered"); + + if (!udata.updated_cb) { + _E("POWER_SUPPLY callback is NULL"); + return; + } + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_NAME"); + if (!val) + return; + info.name = val; + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_STATUS"); + if (!val) + return; + info.status = val; + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_HEALTH"); + if (!val) + return; + info.health = val; + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE"); + if (!val) + return; + info.online = atoi(val); + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_PRESENT"); + if (!val) + return; + info.present = atoi(val); + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY"); + if (!val) + return; + info.capacity = atoi(val); + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW"); + if (!val) + return; + info.current_now = atoi(val); /* uA */ + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG"); + if (!val) + return; + info.current_average = atoi(val); /* uA */ + + ret = get_power_source(&val); + if (ret < 0) + return; + info.power_source = val; + + udata.updated_cb(&info, udata.data); +} + +static struct uevent_handler uh = { + .subsystem = "power_supply", + .uevent_func = uevent_delivered, +}; + +static int battery_register_changed_event( + BatteryUpdated updated_cb, void *data) +{ + int ret; + + ret = uevent_control_kernel_start(); + if (ret < 0) { + _E("Failed to register uevent handler (%d)", ret); + return ret; + } + + ret = register_kernel_event_control(&uh); + if (ret < 0) + _E("Failed to register kernel event control (%d)", ret); + + if (udata.updated_cb == NULL) { + udata.updated_cb = updated_cb; + udata.data = data; + } else + _E("update callback is already registered"); + + return ret; +} + +static void battery_unregister_changed_event( + BatteryUpdated updated_cb) +{ + unregister_kernel_event_control(&uh); + uevent_control_kernel_stop(); + udata.updated_cb = NULL; + udata.data = NULL; +} + +static int battery_get_current_state( + BatteryUpdated updated_cb, void *data) +{ + int ret, val; + struct battery_info info; + char *path; + char status[32]; + char health[32]; + char *power_source; + + if (!updated_cb) + return -EINVAL; + + info.name = BATTERY_HARDWARE_DEVICE_ID; + + path = BATTERY_ROOT_PATH"/battery/status"; + ret = sys_get_str(path, status, sizeof(status)); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + remove_not_string(status); + info.status = status; + + path = BATTERY_ROOT_PATH"/battery/health"; + ret = sys_get_str(path, health, sizeof(health)); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + remove_not_string(health); + info.health = health; + + ret = get_power_source(&power_source); + if (ret < 0) { + _E("Failed to get power source (%d)", ret); + return ret; + } + remove_not_string(power_source); + info.power_source = power_source; + + path = BATTERY_ROOT_PATH"/battery/online"; + ret = sys_get_int(path, &val); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + info.online = val; + + path = BATTERY_ROOT_PATH"/battery/present"; + ret = sys_get_int(path, &val); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + info.present = val; + + path = BATTERY_ROOT_PATH"/battery/capacity"; + ret = sys_get_int(path, &val); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + info.capacity = val; + + path = BATTERY_ROOT_PATH"/battery/current_now"; + ret = sys_get_int(path, &val); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + info.current_now = val; + + path = BATTERY_ROOT_PATH"/battery/current_avg"; + ret = sys_get_int(path, &val); + if (ret < 0) { + _E("Failed to get value of (%s, %d)", path, ret); + return ret; + } + info.current_average = val; + + updated_cb(&info, data); + + return 0; +} + +static int battery_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct battery_device *battery_dev; + + if (!info || !common) + return -EINVAL; + + battery_dev = calloc(1, sizeof(struct battery_device)); + if (!battery_dev) + return -ENOMEM; + + battery_dev->common.info = info; + battery_dev->register_changed_event + = battery_register_changed_event; + battery_dev->unregister_changed_event + = battery_unregister_changed_event; + battery_dev->get_current_state + = battery_get_current_state; + + *common = (struct hw_common *)battery_dev; + return 0; +} + +static int battery_close(struct hw_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = BATTERY_HARDWARE_DEVICE_VERSION, + .id = BATTERY_HARDWARE_DEVICE_ID, + .name = "battery", + .open = battery_open, + .close = battery_close, +}; diff --git a/hw/display/CMakeLists.txt b/hw/display/CMakeLists.txt new file mode 100755 index 0000000..ebccfbe --- /dev/null +++ b/hw/display/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(display C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(display_pkgs REQUIRED hwcommon dlog) + +FOREACH(flag ${display_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE display.c ../shared.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${display_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/display/display.c b/hw/display/display.c new file mode 100755 index 0000000..47af6f3 --- /dev/null +++ b/hw/display/display.c @@ -0,0 +1,147 @@ +/* + * device-node + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include + +#include +#include "../shared.h" + +#ifndef BACKLIGHT_PATH +//#define BACKLIGHT_PATH "/sys/class/backlight/s6e36w1x01-bl" +#define BACKLIGHT_PATH "/sys/class/backlight/s6e8fa0" +#endif + +#define MAX_BRIGHTNESS_TEMP 100 + +static int brightness_temp; + +static int get_max_brightness(int *val) +{ + static int max = -1; + int r; + + if (!val) + return -EINVAL; + + if (max < 0) { + r = sys_get_int(BACKLIGHT_PATH"/max_brightness", &max); + if (r < 0) { + max = MAX_BRIGHTNESS_TEMP; +// return r; + } + } + + *val = max; + return 0; +} + +static int display_get_brightness(int *brightness) +{ + int r, v, max; + + if (!brightness) { + _E("wrong parameter"); + return -EINVAL; + } + + r = get_max_brightness(&max); + if (r < 0) { + _E("fail to get max brightness (errno:%d)", r); + return r; + } + + r = sys_get_int(BACKLIGHT_PATH"/brightness", &v); + if (r < 0) { + _E("fail to get brightness (errno:%d)", r); + v = brightness_temp; +// return r; + } + + *brightness = v * 100.f / max; + return 0; +} + +static int display_set_brightness(int brightness) +{ + int r, v, max; + + if (brightness < 0 || brightness > 100) { + _E("wrong parameter"); + return -EINVAL; + } + + r = get_max_brightness(&max); + if (r < 0) { + _E("fail to get max brightness (errno:%d)", r); + return r; + } + + v = brightness/100.f*max; + r = sys_set_int(BACKLIGHT_PATH"/brightness", v); + if (r < 0) { + _E("fail to set brightness (errno:%d)", r); + brightness_temp = v; +// return r; + } + + return 0; +} + +static int display_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct display_device *display_dev; + + if (!info || !common) + return -EINVAL; + + display_dev = calloc(1, sizeof(struct display_device)); + if (!display_dev) + return -ENOMEM; + + display_dev->common.info = info; + display_dev->get_brightness = display_get_brightness; + display_dev->set_brightness = display_set_brightness; + + *common = (struct hw_common *)display_dev; + return 0; +} + +static int display_close(struct hw_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = DISPLAY_HARDWARE_DEVICE_VERSION, + .id = DISPLAY_HARDWARE_DEVICE_ID, + .name = "Display", + .open = display_open, + .close = display_close, +}; diff --git a/hw/external_connection/CMakeLists.txt b/hw/external_connection/CMakeLists.txt new file mode 100755 index 0000000..4ffccfd --- /dev/null +++ b/hw/external_connection/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(external_connection C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(external_connection_pkgs REQUIRED hwcommon dlog glib-2.0) + +FOREACH(flag ${external_connection_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE external_connection.c ../shared.c ../udev.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${external_connection_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/external_connection/external_connection.c b/hw/external_connection/external_connection.c new file mode 100755 index 0000000..0a94629 --- /dev/null +++ b/hw/external_connection/external_connection.c @@ -0,0 +1,216 @@ +/* + * device-node + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "../shared.h" +#include "../udev.h" + +#define SWITCH_ROOT_PATH "/sys/devices/virtual/switch" + +static struct switch_device { + char *type; + char *name; + int state; +} switch_devices[] = { + { EXTERNAL_CONNECTION_USB, "usb_cable", 0 }, + { EXTERNAL_CONNECTION_DOCK, "dock" , 0 }, + { EXTERNAL_CONNECTION_HEADPHONE, "earjack" , 0 }, +}; + +static struct uevent_data { + ConnectionUpdated updated_cb; + void *data; +} udata = { 0, }; + +static void uevent_delivered(struct udev_device *dev) +{ + struct connection_info info; + char *name, *state; + int i; + + _I("Switch uevent is delivered"); + + name = (char *)udev_device_get_property_value(dev, "SWITCH_NAME"); + if (!name) + return; + + state = (char *)udev_device_get_property_value(dev, "SWITCH_STATE"); + if (!state) + return; + + for (i = 0 ; i < ARRAY_SIZE(switch_devices) ; i++) { + if (strncmp(name, switch_devices[i].name, strlen(name) + 1)) + continue; + + switch_devices[i].state = atoi(state); + + info.name = switch_devices[i].type; + info.state = state; + info.flags = 0; + + if (udata.updated_cb) + udata.updated_cb(&info, udata.data); + else + _E("callback is NULL"); + } +} + +static struct uevent_handler uh = { + .subsystem = "switch", + .uevent_func = uevent_delivered, +}; + +static int external_connection_register_changed_event( + ConnectionUpdated updated_cb, void *data) +{ + int ret; + + ret = uevent_control_kernel_start(); + if (ret < 0) { + _E("Failed to register uevent handler (%d)", ret); + return ret; + } + + ret = register_kernel_event_control(&uh); + if (ret < 0) + _E("Failed to register kernel event control (%d)", ret); + + if (udata.updated_cb == NULL) { + udata.updated_cb = updated_cb; + udata.data = data; + } else + _E("update callback is already registered"); + + return ret; +} + +static void external_connection_unregister_changed_event( + ConnectionUpdated updated_cb) +{ + unregister_kernel_event_control(&uh); + uevent_control_kernel_stop(); + udata.updated_cb = NULL; + udata.data = NULL; +} + +static int read_switch_state(char *path) +{ + char node[128], val[8]; + FILE *fp; + + if (!path) + return -EINVAL; + + snprintf(node, sizeof(node), "%s/%s/state", + SWITCH_ROOT_PATH, path); + + fp = fopen(node, "r"); + if (!fp) { + _E("Failed to open (%s)", path); + return -ENOMEM; + } + + if (!fgets(val, sizeof(val), fp)) { + _E("Failed to read (%s)", path); + fclose(fp); + return -ENOENT; + } + + fclose(fp); + + return atoi(val); +} + +static int external_connection_get_current_state( + ConnectionUpdated updated_cb, void *data) +{ + int ret, i; + struct connection_info info; + char buf[8]; + + if (!updated_cb) + return -EINVAL; + + for (i = 0 ; i < ARRAY_SIZE(switch_devices) ; i++) { + ret = read_switch_state(switch_devices[i].name); + if (ret < 0) { + _E("Failed to get value of (%s, ret:%d)", + switch_devices[i].name, ret); + continue; + } + + info.name = switch_devices[i].type; + snprintf(buf, sizeof(buf), "%d", ret); + info.state = buf; + + updated_cb(&info, data); + } + + return 0; +} + +static int external_connection_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct external_connection_device *external_connection_dev; + + if (!info || !common) + return -EINVAL; + + external_connection_dev = calloc(1, sizeof(struct external_connection_device)); + if (!external_connection_dev) + return -ENOMEM; + + external_connection_dev->common.info = info; + external_connection_dev->register_changed_event + = external_connection_register_changed_event; + external_connection_dev->unregister_changed_event + = external_connection_unregister_changed_event; + external_connection_dev->get_current_state + = external_connection_get_current_state; + + *common = (struct hw_common *)external_connection_dev; + return 0; +} + +static int external_connection_close(struct hw_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = EXTERNAL_CONNECTION_HARDWARE_DEVICE_VERSION, + .id = EXTERNAL_CONNECTION_HARDWARE_DEVICE_ID, + .name = "external_connection", + .open = external_connection_open, + .close = external_connection_close, +}; diff --git a/hw/shared.c b/hw/shared.c new file mode 100755 index 0000000..b6401c1 --- /dev/null +++ b/hw/shared.c @@ -0,0 +1,129 @@ +/* + * device-node + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define BUF_MAX 255 + +static int sys_read_buf(char *file, char *buf, int len) +{ + int fd, r; + + if (!file || !buf || len < 0) + return -EINVAL; + + fd = open(file, O_RDONLY); + if (fd == -1) + return -ENOENT; + + r = read(fd, buf, len); + close(fd); + if ((r >= 0) && (r < len)) + buf[r] = '\0'; + else + return -EIO; + + return 0; +} + +static int sys_write_buf(char *file, char *buf) +{ + int fd, r; + + if (!file || !buf) + return -EINVAL; + + fd = open(file, O_WRONLY); + if (fd == -1) + return -EPERM; + + r = write(fd, buf, strlen(buf)); + close(fd); + if (r < 0) + return -EIO; + + return 0; +} + +int sys_get_int(char *fname, int *val) +{ + char buf[BUF_MAX]; + int r; + + if (!fname || !val) + return -EINVAL; + + r = sys_read_buf(fname, buf, sizeof(buf)); + if (r < 0) + return r; + + *val = atoi(buf); + return 0; +} + +int sys_get_str(char *fname, char *str, int len) +{ + int r; + + if (!fname || !str || len < 0) + return -EINVAL; + + r = sys_read_buf(fname, str, len); + if (r < 0) + return r; + + return 0; +} + +int sys_set_int(char *fname, int val) +{ + char buf[BUF_MAX]; + int r; + + if (!fname) + return -EINVAL; + + snprintf(buf, sizeof(buf), "%d", val); + r = sys_write_buf(fname, buf); + if (r < 0) + return r; + + return 0; +} + +int sys_set_str(char *fname, char *val) +{ + int r; + + if (!fname || !val) + return -EINVAL; + + r = sys_write_buf(fname, val); + if (r < 0) + return r; + + return 0; +} diff --git a/hw/shared.h b/hw/shared.h new file mode 100755 index 0000000..da51ca4 --- /dev/null +++ b/hw/shared.h @@ -0,0 +1,43 @@ +/* + * libdevice-node + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 __HW_DEFAULT_SHARED_H__ +#define __HW_DEFAULT_SHARED_H__ + +#define FEATURE_HARDWARE_DLOG +#ifdef FEATURE_HARDWARE_DLOG +#define LOG_TAG "HARDWARE" +#include +#define _I(fmt, args...) SLOGI(fmt, ##args) +#define _D(fmt, args...) SLOGD(fmt, ##args) +#define _E(fmt, args...) SLOGE(fmt, ##args) +#else +#define _I(x, ...) do { } while (0) +#define _D(x, ...) do { } while (0) +#define _E(x, ...) do { } while (0) +#endif + +#define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0])) + +int sys_get_int(char *fname, int *val); +int sys_get_str(char *fname, char *str, int len); +int sys_set_int(char *fname, int val); +int sys_set_str(char *fname, char *val); + +#endif diff --git a/hw/touchscreen/CMakeLists.txt b/hw/touchscreen/CMakeLists.txt new file mode 100755 index 0000000..b097615 --- /dev/null +++ b/hw/touchscreen/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(touchscreen C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(touchscreen_pkgs REQUIRED hwcommon dlog) + +FOREACH(flag ${touchscreen_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE touchscreen.c ../shared.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${touchscreen_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/touchscreen/touchscreen.c b/hw/touchscreen/touchscreen.c new file mode 100755 index 0000000..1d5be64 --- /dev/null +++ b/hw/touchscreen/touchscreen.c @@ -0,0 +1,178 @@ +/* + * device-node + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include "../shared.h" + +#define INPUT_PATH "/sys/class/input/" +#define KEY_CAPABILITIES_PATH "/device/capabilities/key" +#define ENABLED_PATH "/device/enabled" +#define TOUCHSCREEN_CAPABILITY 400 + +#define TURNON_TOUCHSCREEN 1 +#define TURNOFF_TOUCHSCREEN 0 + +static char *touchscreen_node; + +static int touchscreen_probe(void) +{ + DIR *d; + struct dirent entry; + struct dirent *dir; + char buf[PATH_MAX]; + int val, ret = -ENOTSUP; + + d = opendir(INPUT_PATH); + if (!d) + return -errno; + + while (readdir_r(d, &entry, &dir) == 0 && dir != NULL) { + if (dir->d_name[0] == '.') + continue; + snprintf(buf, sizeof(buf), "%s%s%s", INPUT_PATH, + dir->d_name, KEY_CAPABILITIES_PATH); + + ret = sys_get_int(buf, &val); + if (ret < 0 || val != TOUCHSCREEN_CAPABILITY) + continue; + + snprintf(buf, sizeof(buf), "%s%s%s", INPUT_PATH, + dir->d_name, ENABLED_PATH); + + touchscreen_node = strndup(buf, strlen(buf)); + if (touchscreen_node) { + _I("touchscreen node (%s)", touchscreen_node); + ret = 0; + } else { + _E("strndup() failed"); + ret = -ENOMEM; + } + break; + } + closedir(d); + + return ret; +} + +static int touchscreen_get_state(enum touchscreen_state *state) +{ + int ret, val; + + if (!touchscreen_node || !(*touchscreen_node)) + return -ENOENT; + + if (!state) + return -EINVAL; + + ret = sys_get_int(touchscreen_node, &val); + if (ret < 0) { + _E("Failed to get touchscreen state (%d)", ret); + return ret; + } + + switch (val) { + case TURNOFF_TOUCHSCREEN: + *state = TOUCHSCREEN_OFF; + break; + case TURNON_TOUCHSCREEN: + *state = TOUCHSCREEN_ON; + break; + default: + _E("Failed to get touchscreen state (%d)", val); + return -EINVAL; + } + + return 0; +} + +static int touchscreen_set_state(enum touchscreen_state state) +{ + int ret, val; + + if (!touchscreen_node || !(*touchscreen_node)) + return -ENOENT; + + switch (state) { + case TOUCHSCREEN_OFF: + val = TURNOFF_TOUCHSCREEN; + break; + case TOUCHSCREEN_ON: + val = TURNON_TOUCHSCREEN; + break; + default: + _E("Invalid input (%d)", state); + return -EINVAL; + } + + ret = sys_set_int(touchscreen_node, val); + if (ret < 0) + _E("Failed to change touchscreen state (%d)", ret); + + return ret; +} + +static int touchscreen_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct touchscreen_device *touchscreen_dev; + + if (!info || !common) + return -EINVAL; + + if (touchscreen_probe() < 0) + return -ENOTSUP; + + touchscreen_dev = calloc(1, sizeof(struct touchscreen_device)); + if (!touchscreen_dev) + return -ENOMEM; + + touchscreen_dev->common.info = info; + touchscreen_dev->get_state = touchscreen_get_state; + touchscreen_dev->set_state = touchscreen_set_state; + + *common = (struct hw_common *)touchscreen_dev; + return 0; +} + +static int touchscreen_close(struct hw_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + free(touchscreen_node); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = TOUCHSCREEN_HARDWARE_DEVICE_VERSION, + .id = TOUCHSCREEN_HARDWARE_DEVICE_ID, + .name = "touchscreen", + .open = touchscreen_open, + .close = touchscreen_close, +}; diff --git a/hw/udev.c b/hw/udev.c new file mode 100755 index 0000000..562725b --- /dev/null +++ b/hw/udev.c @@ -0,0 +1,298 @@ +/* + * device-manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include "shared.h" +#include "udev.h" + +#define EVENT_KERNEL "kernel" +#define EVENT_UDEV "udev" + +#define UDEV_MONITOR_SIZE (10*1024) + +struct uevent_info { + struct udev_monitor *mon; + GIOChannel *ch; + guint eventid; + GList *event_list; +}; + + +/* Uevent */ +static struct udev *udev; +static struct uevent_info kevent; /* kernel */ +static struct uevent_info uevent; /* udev */ + +static gboolean uevent_control_cb(GIOChannel *channel, + GIOCondition cond, void *data) +{ + struct uevent_info *info = data; + struct udev_device *dev; + struct uevent_handler *l; + GList *elem; + const char *subsystem; + int len; + + if (!info) { + _E("data is invalid"); + return TRUE; + } + + dev = udev_monitor_receive_device(info->mon); + if (!dev) + return TRUE; + + subsystem = udev_device_get_subsystem(dev); + if (!subsystem) + goto out; + + len = strlen(subsystem); + + for (elem = info->event_list ; elem ; elem = g_list_next(elem)) { + l = elem->data; + if (!l) + continue; + if (!strncmp(l->subsystem, subsystem, len) && + l->uevent_func) + l->uevent_func(dev); + } + +out: + udev_device_unref(dev); + return TRUE; +} + +static int uevent_control_stop(struct uevent_info *info) +{ + struct udev_device *dev; + + if (!info) + return -EINVAL; + + if (info->eventid) { + g_source_remove(info->eventid); + info->eventid = 0; + } + if (info->ch) { + g_io_channel_unref(info->ch); + info->ch = NULL; + } + if (info->mon) { + dev = udev_monitor_receive_device(info->mon); + if (dev) + udev_device_unref(dev); + udev_monitor_unref(info->mon); + info->mon = NULL; + } + if (udev) + udev = udev_unref(udev); + return 0; +} + +static int uevent_control_start(const char *type, + struct uevent_info *info) +{ + struct uevent_handler *l; + GList *elem; + int fd; + int ret; + + if (!info) + return -EINVAL; + + if (info->mon) { + _E("%s uevent control routine is alreay started", type); + return -EINVAL; + } + + if (!udev) { + udev = udev_new(); + if (!udev) { + _E("error create udev"); + return -EINVAL; + } + } else + udev = udev_ref(udev); + + info->mon = udev_monitor_new_from_netlink(udev, type); + if (info->mon == NULL) { + _E("error udev_monitor create"); + goto stop; + } + + ret = udev_monitor_set_receive_buffer_size(info->mon, + UDEV_MONITOR_SIZE); + if (ret != 0) { + _E("fail to set receive buffer size"); + goto stop; + } + + for (elem = info->event_list ; elem ; elem = g_list_next(elem)) { + l = elem->data; + ret = udev_monitor_filter_add_match_subsystem_devtype( + info->mon, + l->subsystem, NULL); + if (ret < 0) { + _E("error apply subsystem filter"); + goto stop; + } + } + + ret = udev_monitor_filter_update(info->mon); + if (ret < 0) + _E("error udev_monitor_filter_update"); + + fd = udev_monitor_get_fd(info->mon); + if (fd == -1) { + _E("error udev_monitor_get_fd"); + goto stop; + } + + info->ch = g_io_channel_unix_new(fd); + info->eventid = g_io_add_watch(info->ch, + G_IO_IN, uevent_control_cb, info); + if (info->eventid == 0) { + _E("Failed to add channel watch"); + goto stop; + } + + if (udev_monitor_enable_receiving(info->mon) < 0) { + _E("error unable to subscribe to udev events"); + goto stop; + } + + return 0; +stop: + uevent_control_stop(info); + return -EINVAL; +} + +int uevent_control_kernel_start(void) +{ + return uevent_control_start(EVENT_KERNEL, &kevent); +} + +void uevent_control_kernel_stop(void) +{ + uevent_control_stop(&kevent); +} + +int uevent_control_udev_start(void) +{ + return uevent_control_start(EVENT_UDEV, &uevent); +} + +void uevent_control_udev_stop(void) +{ + uevent_control_stop(&uevent); +} + +static int register_uevent_control(struct uevent_info *info, + struct uevent_handler *uh) +{ + struct uevent_handler *l; + GList *elem; + int r; + bool matched = false; + int len; + + if (!info || !uh || !uh->subsystem) + return -EINVAL; + + /* if udev is not initialized, it just will be added list */ + if (!udev || !info->mon) + goto add_list; + + len = strlen(uh->subsystem); + /* check if the same subsystem is already added */ + for (elem = info->event_list; elem ; elem = g_list_next(elem)) { + l = elem->data; + if (!strncmp(l->subsystem, uh->subsystem, len)) { + matched = true; + break; + } + } + + /* the first request to add subsystem */ + if (!matched) { + r = udev_monitor_filter_add_match_subsystem_devtype(info->mon, + uh->subsystem, NULL); + if (r < 0) { + _E("fail to add %s subsystem : %d", uh->subsystem, r); + return -EPERM; + } + } + + r = udev_monitor_filter_update(info->mon); + if (r < 0) + _E("fail to update udev monitor filter : %d", r); + +add_list: + info->event_list = g_list_append(info->event_list, uh); + return 0; +} + +static int unregister_uevent_control(struct uevent_info *info, + const struct uevent_handler *uh) +{ + struct uevent_handler *l; + GList *n, *next; + int len; + + if (!info || !uh || !uh->subsystem) + return -EINVAL; + + len = strlen(uh->subsystem); + for (n = info->event_list, next = g_list_next(n) ; + n ; n = next, next = g_list_next(n)) { + l = n->data; + if (!strncmp(l->subsystem, uh->subsystem, len) && + l->uevent_func == uh->uevent_func) { + info->event_list = g_list_delete_link(info->event_list, n); + return 0; + } + } + + return -ENOENT; +} + +int register_kernel_event_control(struct uevent_handler *uh) +{ + return register_uevent_control(&kevent, uh); +} + +void unregister_kernel_event_control(struct uevent_handler *uh) +{ + unregister_uevent_control(&kevent, uh); +} + +int register_udev_event_control(struct uevent_handler *uh) +{ + return register_uevent_control(&uevent, uh); +} + +void unregister_udev_event_control(struct uevent_handler *uh) +{ + unregister_uevent_control(&uevent, uh); +} diff --git a/hw/udev.h b/hw/udev.h new file mode 100755 index 0000000..d2aeff1 --- /dev/null +++ b/hw/udev.h @@ -0,0 +1,43 @@ +/* + * device-manager + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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 __UDEV_H__ +#define __UDEV_H__ + +#include + +struct uevent_handler { + const char *subsystem; + void (*uevent_func)(struct udev_device *dev); + void *data; +}; + +int uevent_control_kernel_start(void); +void uevent_control_kernel_stop(void); + +int uevent_control_udev_start(void); +void uevent_control_udev_stop(void); + +int register_kernel_event_control(struct uevent_handler *uh); +void unregister_kernel_event_control(struct uevent_handler *uh); + +int register_udev_event_control(struct uevent_handler *uh); +void unregister_udev_event_control(struct uevent_handler *uh); + +#endif /* __UDEV_H__ */ diff --git a/packaging/device-manager-plugin-artik.manifest b/packaging/device-manager-plugin-artik.manifest new file mode 100755 index 0000000..af9b883 --- /dev/null +++ b/packaging/device-manager-plugin-artik.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/device-manager-plugin-artik.spec b/packaging/device-manager-plugin-artik.spec new file mode 100755 index 0000000..9538a3a --- /dev/null +++ b/packaging/device-manager-plugin-artik.spec @@ -0,0 +1,42 @@ +Name: device-manager-plugin-artik +Summary: Device manager plugin artik +Version: 0.0.1 +Release: 0 +Group: System/Hardware Adaptation +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1: %{name}.manifest +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(hwcommon) +BuildRequires: pkgconfig(glib-2.0) + +%description +Device manager plugin artik + + +%prep +%setup -q +cp %{SOURCE1} . + +%build +%cmake . + +make %{?jobs:-j%jobs} + +%install +%make_install + + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%{_libdir}/hw/*.so +%manifest %{name}.manifest +%license LICENSE -- 2.7.4 From 03f4e419c76489cef2c44622f815e88563b1f733 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 7 Jul 2016 17:33:23 +0900 Subject: [PATCH 03/11] battery: change sysfw nodes according to the artik driver - Artik driver is little bit different with other devices. Thus HAL needs to be changed according to the artik driver. Change-Id: I9252da1658a9bbfec60f954e384adc2aac688a2f Signed-off-by: taeyoung --- hw/battery/battery.c | 96 +++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/hw/battery/battery.c b/hw/battery/battery.c index 0ff4fc9..6baf474 100755 --- a/hw/battery/battery.c +++ b/hw/battery/battery.c @@ -42,24 +42,12 @@ static int get_power_source(char **src) if (!src) return -EINVAL; - ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_AC"/online", &val); + ret = sys_get_int(BATTERY_ROOT_PATH"/rk-ac/online", &val); if (ret >= 0 && val > 0) { *src = POWER_SOURCE_AC; return 0; } - ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_USB"/online", &val); - if (ret >= 0 && val > 0) { - *src = POWER_SOURCE_USB; - return 0; - } - - ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_WIRELESS"/online", &val); - if (ret >= 0 && val > 0) { - *src = POWER_SOURCE_WIRELESS; - return 0; - } - *src = POWER_SOURCE_NONE; return 0; @@ -107,36 +95,43 @@ static void uevent_delivered(struct udev_device *dev) return; info.health = val; - val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE"); - if (!val) - return; - info.online = atoi(val); - val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_PRESENT"); if (!val) return; info.present = atoi(val); + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE"); + if (val) + info.online = atoi(val); + else + info.online = info.present; + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY"); if (!val) return; info.capacity = atoi(val); - val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW"); - if (!val) - return; - info.current_now = atoi(val); /* uA */ - - val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG"); - if (!val) - return; - info.current_average = atoi(val); /* uA */ - ret = get_power_source(&val); if (ret < 0) return; info.power_source = val; + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW"); + if (val) + info.current_now = atoi(val); /* uA */ + else { + if (strncmp(info.power_source, POWER_SOURCE_NONE, sizeof(POWER_SOURCE_NONE))) + info.current_now = 1000; /* current entering the battery from charge source */ + else + info.current_now = -1000; /* current discharging from the battery */ + } + + val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG"); + if (val) + info.current_average = atoi(val); /* uA */ + else + info.current_average = info.current_now; + udata.updated_cb(&info, udata.data); } @@ -193,7 +188,7 @@ static int battery_get_current_state( info.name = BATTERY_HARDWARE_DEVICE_ID; - path = BATTERY_ROOT_PATH"/battery/status"; + path = BATTERY_ROOT_PATH"/rk-bat/status"; ret = sys_get_str(path, status, sizeof(status)); if (ret < 0) { _E("Failed to get value of (%s, %d)", path, ret); @@ -202,7 +197,7 @@ static int battery_get_current_state( remove_not_string(status); info.status = status; - path = BATTERY_ROOT_PATH"/battery/health"; + path = BATTERY_ROOT_PATH"/rk-bat/health"; ret = sys_get_str(path, health, sizeof(health)); if (ret < 0) { _E("Failed to get value of (%s, %d)", path, ret); @@ -219,23 +214,22 @@ static int battery_get_current_state( remove_not_string(power_source); info.power_source = power_source; - path = BATTERY_ROOT_PATH"/battery/online"; + path = BATTERY_ROOT_PATH"/rk-bat/present"; ret = sys_get_int(path, &val); if (ret < 0) { _E("Failed to get value of (%s, %d)", path, ret); return ret; } - info.online = val; + info.present = val; - path = BATTERY_ROOT_PATH"/battery/present"; + path = BATTERY_ROOT_PATH"/rk-bat/online"; ret = sys_get_int(path, &val); - if (ret < 0) { - _E("Failed to get value of (%s, %d)", path, ret); - return ret; - } - info.present = val; + if (ret == 0) + info.online = val; + else + info.online = info.present; - path = BATTERY_ROOT_PATH"/battery/capacity"; + path = BATTERY_ROOT_PATH"/rk-bat/capacity"; ret = sys_get_int(path, &val); if (ret < 0) { _E("Failed to get value of (%s, %d)", path, ret); @@ -243,21 +237,23 @@ static int battery_get_current_state( } info.capacity = val; - path = BATTERY_ROOT_PATH"/battery/current_now"; + path = BATTERY_ROOT_PATH"/rk-bat/current_now"; ret = sys_get_int(path, &val); - if (ret < 0) { - _E("Failed to get value of (%s, %d)", path, ret); - return ret; + if (ret == 0) + info.current_now = val; + else { + if (strncmp(power_source, POWER_SOURCE_NONE, sizeof(POWER_SOURCE_NONE))) + info.current_now = 1000; /* current entering the battery from charge source */ + else + info.current_now = -1000; /* current discharging from the battery */ } - info.current_now = val; - path = BATTERY_ROOT_PATH"/battery/current_avg"; + path = BATTERY_ROOT_PATH"/rk-bat/current_avg"; ret = sys_get_int(path, &val); - if (ret < 0) { - _E("Failed to get value of (%s, %d)", path, ret); - return ret; - } - info.current_average = val; + if (ret == 0) + info.current_average = val; + else + info.current_average = info.current_now; updated_cb(&info, data); -- 2.7.4 From 50ef994cb9061d1632542685b410717c607ec292 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 7 Jul 2016 10:42:02 +0900 Subject: [PATCH 04/11] display: return raw brightness value - The brightness value from driver is returned to device daemon. device daemon will calculate it for users Change-Id: I8823352e0b3f85c3b563c75725e0e8b46aea7841 Signed-off-by: taeyoung --- hw/display/display.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/hw/display/display.c b/hw/display/display.c index 47af6f3..0eb19cb 100755 --- a/hw/display/display.c +++ b/hw/display/display.c @@ -35,7 +35,7 @@ static int brightness_temp; -static int get_max_brightness(int *val) +static int display_get_max_brightness(int *val) { static int max = -1; int r; @@ -57,50 +57,43 @@ static int get_max_brightness(int *val) static int display_get_brightness(int *brightness) { - int r, v, max; + int r, v; if (!brightness) { _E("wrong parameter"); return -EINVAL; } - r = get_max_brightness(&max); - if (r < 0) { - _E("fail to get max brightness (errno:%d)", r); - return r; - } - r = sys_get_int(BACKLIGHT_PATH"/brightness", &v); if (r < 0) { - _E("fail to get brightness (errno:%d)", r); + _E("fail to get brightness : %d", r); v = brightness_temp; // return r; } - *brightness = v * 100.f / max; + *brightness = v; return 0; } static int display_set_brightness(int brightness) { - int r, v, max; + int r, max; - if (brightness < 0 || brightness > 100) { - _E("wrong parameter"); - return -EINVAL; - } - - r = get_max_brightness(&max); + r = display_get_max_brightness(&max); if (r < 0) { _E("fail to get max brightness (errno:%d)", r); return r; } - v = brightness/100.f*max; - r = sys_set_int(BACKLIGHT_PATH"/brightness", v); + if (brightness < 0 || brightness > max) { + _E("wrong parameter"); + return -EINVAL; + } + + r = sys_set_int(BACKLIGHT_PATH"/brightness", brightness); if (r < 0) { _E("fail to set brightness (errno:%d)", r); - brightness_temp = v; + brightness_temp = brightness; // return r; } @@ -120,6 +113,7 @@ static int display_open(struct hw_info *info, return -ENOMEM; display_dev->common.info = info; + display_dev->get_max_brightness = display_get_max_brightness; display_dev->get_brightness = display_get_brightness; display_dev->set_brightness = display_set_brightness; -- 2.7.4 From dddebdc205c3499c325e6db79a5a19a8e6c19566 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Mon, 5 Sep 2016 11:38:11 +0900 Subject: [PATCH 05/11] common: add libudev dependency - Add libudev dependency explicitly Change-Id: I89ebd7a66e800d1a66224143620d440cc3991129 Signed-off-by: taeyoung --- hw/battery/CMakeLists.txt | 2 +- hw/external_connection/CMakeLists.txt | 2 +- packaging/device-manager-plugin-artik.spec | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/battery/CMakeLists.txt b/hw/battery/CMakeLists.txt index 9703427..48ef1aa 100755 --- a/hw/battery/CMakeLists.txt +++ b/hw/battery/CMakeLists.txt @@ -4,7 +4,7 @@ PROJECT(battery C) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) INCLUDE(FindPkgConfig) -pkg_check_modules(battery_pkgs REQUIRED hwcommon dlog glib-2.0) +pkg_check_modules(battery_pkgs REQUIRED hwcommon dlog glib-2.0 libudev) FOREACH(flag ${battery_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/hw/external_connection/CMakeLists.txt b/hw/external_connection/CMakeLists.txt index 4ffccfd..e700a2f 100755 --- a/hw/external_connection/CMakeLists.txt +++ b/hw/external_connection/CMakeLists.txt @@ -4,7 +4,7 @@ PROJECT(external_connection C) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) INCLUDE(FindPkgConfig) -pkg_check_modules(external_connection_pkgs REQUIRED hwcommon dlog glib-2.0) +pkg_check_modules(external_connection_pkgs REQUIRED hwcommon dlog glib-2.0 libudev) FOREACH(flag ${external_connection_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/packaging/device-manager-plugin-artik.spec b/packaging/device-manager-plugin-artik.spec index 9538a3a..8b2db3a 100755 --- a/packaging/device-manager-plugin-artik.spec +++ b/packaging/device-manager-plugin-artik.spec @@ -12,6 +12,7 @@ BuildRequires: cmake BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(hwcommon) BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(libudev) %description Device manager plugin artik -- 2.7.4 From 591890fa032a9ddde1d5b1d22f1f8625170e4264 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Fri, 9 Sep 2016 20:27:41 +0900 Subject: [PATCH 06/11] Add USB gadget HAL implementation USB gadget HAL is an abstraction layer which translates set of functions into full USB gadget description specific for this particular device. Change-Id: I41d38c3d6dfd0c732b3c3a22b71713069618c309 Signed-off-by: Krzysztof Opasiak --- CMakeLists.txt | 3 +- hw/usb_gadget/CMakeLists.txt | 19 +++ hw/usb_gadget/usb_gadget.c | 392 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 hw/usb_gadget/CMakeLists.txt create mode 100644 hw/usb_gadget/usb_gadget.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0414f0c..6e31fe0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(device-manager-exynos3250 C) +PROJECT(device-manager-artik C) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) @@ -7,3 +7,4 @@ ADD_SUBDIRECTORY(hw/battery) ADD_SUBDIRECTORY(hw/display) ADD_SUBDIRECTORY(hw/external_connection) ADD_SUBDIRECTORY(hw/touchscreen) +ADD_SUBDIRECTORY(hw/usb_gadget) diff --git a/hw/usb_gadget/CMakeLists.txt b/hw/usb_gadget/CMakeLists.txt new file mode 100644 index 0000000..2e28b15 --- /dev/null +++ b/hw/usb_gadget/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(usb_gadget C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(usb_gadget_pkgs REQUIRED hwcommon) + +FOREACH(flag ${usb_gadget_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE usb_gadget.c ../shared.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${usb_gadget_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/usb_gadget/usb_gadget.c b/hw/usb_gadget/usb_gadget.c new file mode 100644 index 0000000..0bcb10b --- /dev/null +++ b/hw/usb_gadget/usb_gadget.c @@ -0,0 +1,392 @@ +/* + * libdevice-node + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * 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 __HW_USB_GADGET_SIMPLE_TRANSLATOR_H__ + +#include + +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +#define zalloc(amount) calloc(1, amount) + +/* Based on slp-gadget and initial version of USB HAL by Taeyoung Kim */ +#define DEFAULT_VID 0x04e8 +#define DEFAULT_PID 0x6860 +#define DEFAULT_BCD_DEVICE 0xffff + +#define DEFAULT_LANG 0x409 /* US_en */ +#define DEFAULT_MANUFACTURER "Samsung" +#define DEFAULT_PRODUCT "TIZEN" +#define DEFAULT_SERIAL "01234TEST" + +#define DEFAULT_BMATTRIBUTES ((1 << 7) | (1 << 6)) +#define DEFAULT_MAX_POWER 500 + +static void simple_cleanup_config(struct usb_configuration *config) +{ + int i; + + if (!config) + return; + + if (config->strs) { + for (i = 0; config->strs[i].lang_code; ++i) + free(config->strs[i].config_str); + + free(config->strs); + } + + /* + * Each function will be free later, + * for now we cleanup only pointers. + */ + if (config->funcs) + free(config->funcs); + + free(config); +} + +static void simple_cleanup_gadget(struct usb_gadget *gadget) +{ + int i; + + if (!gadget) + return; + + if (gadget->strs) { + for (i = 0; gadget->strs[i].lang_code; ++i) { + free(gadget->strs[i].manufacturer); + free(gadget->strs[i].product); + free(gadget->strs[i].serial); + } + free(gadget->strs); + } + + if (gadget->configs) { + for (i = 0; gadget->configs[i]; ++i) + simple_cleanup_config(gadget->configs[i]); + + free(gadget->configs); + } + + if (gadget->funcs) { + for (i = 0; gadget->funcs[i]; ++i) + gadget->funcs[i]->free_func(gadget->funcs[i]); + + free(gadget->funcs); + } + + free(gadget); +} + +static int alloc_default_config(struct usb_configuration **_config) +{ + struct usb_configuration *config; + + config = zalloc(sizeof(*config)); + if (!config) + goto out; + + config->strs = calloc(1, sizeof(*config->strs)); + if (!config->strs) + goto free_config; + + config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES; + config->attrs.MaxPower = DEFAULT_MAX_POWER; + + *_config = config; + + return 0; + +free_config: + free(config); +out: + return -ENOMEM; +} + +static int alloc_default_gadget(struct usb_gadget **_gadget) +{ + struct usb_gadget *gadget; + struct usb_gadget_strings *strs; + struct usb_configuration **configs; + + gadget = zalloc(sizeof(*gadget)); + if (!gadget) + goto out; + + gadget->attrs.idVendor = DEFAULT_VID; + gadget->attrs.idProduct = DEFAULT_PID; + gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE; + + strs = calloc(2, sizeof(*strs)); + if (!strs) + goto free_gadget; + + strs[0].lang_code = 0x409; + strs[0].manufacturer = strdup(DEFAULT_MANUFACTURER); + strs[0].product = strdup(DEFAULT_PRODUCT); + strs[0].serial = strdup(DEFAULT_SERIAL); + + if (!strs[0].manufacturer || !strs[0].product || !strs[0].serial) + goto free_strs; + + gadget->strs = strs; + + /* slp-gadget use max 2 confiuration and NULL termination */ + configs = calloc(3, sizeof(*configs)); + if (!configs) + goto free_strs; + + gadget->configs = configs; + *_gadget = gadget; + + return 0; + +free_strs: + free(strs[0].manufacturer); + free(strs[0].product); + free(strs[0].serial); + free(strs); +free_gadget: + free(gadget); +out: + return -ENOMEM; +} + +static inline struct usb_function *find_func(struct usb_gadget *gadget, + int func_id) +{ + int i; + + for (i = 0; gadget->funcs[i] && gadget->funcs[i]->id != func_id; ++i); + + return gadget->funcs[i]; +} + +static int simple_id_to_gadget(struct usb_gadget_id *gadget_id, + struct usb_gadget **_gadget) +{ + struct usb_gadget *gadget; + int n_configs; + /* zero terminates */ + int functions[2][sizeof(gadget_id->function_mask)*8]; + int n_functions; + struct usb_function **funcs; + int idx, i, j; + int ret; + + if (!gadget_id || !_gadget) + return -EINVAL; + + ret = alloc_default_gadget(&gadget); + if (ret) + goto out; + + /* + * Currently all gadgets use inly single configuration but + * slp-gadget is capable to handle two of them + * + * Order of interfaces in configuration is significant + * so in this switch we sort our functions in a correct order + */ + switch (gadget_id->function_mask) { + case USB_FUNCTION_SDB: + n_configs = 1; + functions[0][0] = USB_FUNCTION_SDB; + functions[0][1] = 0; + gadget->attrs.idProduct = 0x685d; + break; + case USB_FUNCTION_MTP: + n_configs = 1; + functions[0][0] = USB_FUNCTION_MTP; + functions[0][1] = 0; + gadget->attrs.idProduct = 0x6860; + break; + case USB_FUNCTION_RNDIS: + n_configs = 1; + functions[0][0] = USB_FUNCTION_RNDIS; + functions[0][1] = 0; + gadget->attrs.idProduct = 0x6863; + break; + case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB: + n_configs = 1; + functions[0][0] = USB_FUNCTION_MTP; + functions[0][1] = USB_FUNCTION_ACM; + functions[0][2] = USB_FUNCTION_SDB; + functions[0][3] = 0; + gadget->attrs.idProduct = 0x6860; + break; + case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB + | USB_FUNCTION_DIAG: + n_configs = 1; + functions[0][0] = USB_FUNCTION_MTP; + functions[0][1] = USB_FUNCTION_ACM; + functions[0][2] = USB_FUNCTION_SDB; + functions[0][3] = USB_FUNCTION_DIAG; + functions[0][4] = 0; + gadget->attrs.idProduct = 0x6860; + break; + case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB: + n_configs = 1; + functions[0][0] = USB_FUNCTION_RNDIS; + functions[0][1] = USB_FUNCTION_SDB; + functions[0][2] = 0; + gadget->attrs.idProduct = 0x6864; + break; + case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM | USB_FUNCTION_DIAG: + n_configs = 1; + functions[0][0] = USB_FUNCTION_RNDIS; + functions[0][1] = USB_FUNCTION_SDB; + functions[0][2] = USB_FUNCTION_ACM; + functions[0][3] = USB_FUNCTION_DIAG; + functions[0][4] = 0; + gadget->attrs.idProduct = 0x6864; + break; + case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG: + n_configs = 1; + functions[0][0] = USB_FUNCTION_RNDIS; + functions[0][1] = USB_FUNCTION_DIAG; + functions[0][2] = 0; + gadget->attrs.idProduct = 0x6864; + break; + case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM: + n_configs = 1; + functions[0][0] = USB_FUNCTION_ACM; + functions[0][1] = USB_FUNCTION_SDB; + functions[0][2] = USB_FUNCTION_DM; + functions[0][3] = 0; + gadget->attrs.idProduct = 0x6860; + break; + case USB_FUNCTION_DIAG | USB_FUNCTION_ACM | USB_FUNCTION_RMNET: + n_configs = 1; + functions[0][0] = USB_FUNCTION_DIAG; + functions[0][1] = USB_FUNCTION_ACM; + functions[0][2] = USB_FUNCTION_RMNET; + functions[0][3] = 0; + gadget->attrs.idProduct = 0x685d; + break; + }; + + if (n_configs > 2) { + ret = -EINVAL; + goto free_gadget; + } + + n_functions = __builtin_popcount(gadget_id->function_mask); + + funcs = calloc(n_functions + 1, sizeof(*funcs)); + if (!funcs) { + ret = -ENOMEM; + goto free_gadget; + } + + gadget->funcs = funcs; + + idx = 0; + for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i) { + int func_id = 1 << i; + + if (!(gadget_id->function_mask & func_id)) + continue; + + ret = _available_funcs[i]->clone(_available_funcs[i], + gadget->funcs + idx); + if (ret) + goto free_functions; + ++idx; + } + + for (j = 0; j < n_configs; ++j) { + struct usb_configuration *config; + int n_funcs_in_config; + + for (i = 0; functions[j][i]; ++i); + n_funcs_in_config = i; + + ret = alloc_default_config(&config); + if (ret) + goto free_configs; + + gadget->configs[j] = config; + config->funcs = calloc(n_funcs_in_config + 1, + sizeof(void *)); + if (!config->funcs) + goto free_configs; + + for (i = 0; functions[j][i]; ++i) + config->funcs[i] = find_func(gadget, functions[j][i]); + } + + *_gadget = gadget; + return 0; +free_configs: +free_functions: +free_gadget: + simple_cleanup_gadget(gadget); +out: + return ret; +} + +static int simple_translator_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct usb_gadget_translator *simple_translator; + + if (!info || !common) + return -EINVAL; + + simple_translator = zalloc(sizeof(*simple_translator)); + if (!simple_translator) + return -ENOMEM; + + simple_translator->common.info = info; + simple_translator->id_to_gadget = simple_id_to_gadget; + simple_translator->cleanup_gadget = simple_cleanup_gadget; + + *common = &simple_translator->common; + return 0; +} + +static int simple_translator_close(struct hw_common *common) +{ + struct usb_gadget_translator *simple_translator; + + if (!common) + return -EINVAL; + + simple_translator = container_of(common, struct usb_gadget_translator, + common); + + free(simple_translator); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = USB_GADGET_DEVICE_VERSION, + .id = USB_GADGET_DEVICE_ID, + .name = "simple_translator", + .open = simple_translator_open, + .close = simple_translator_close, +}; + +#endif -- 2.7.4 From ebcf7b41762c202164a5e75a220f9c25f8a78b7f Mon Sep 17 00:00:00 2001 From: taeyoung Date: Fri, 9 Sep 2016 20:30:02 +0900 Subject: [PATCH 07/11] Add USB config HAL implementation for slp-gadget This implementation of USB config HAL allows to apply abstract gadget description received from USB gadget HAL to USB gadget subsystem in Kernel via slp-gadget sysfs interface. Change-Id: I3a621c9af78339b582bb46a5c3939bd52ab3e6d2 Signed-off-by: Krzysztof Opasiak --- CMakeLists.txt | 1 + hw/usb_client/CMakeLists.txt | 19 ++ hw/usb_client/usb_client.c | 646 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 666 insertions(+) create mode 100644 hw/usb_client/CMakeLists.txt create mode 100644 hw/usb_client/usb_client.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e31fe0..06d4bc9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,3 +8,4 @@ ADD_SUBDIRECTORY(hw/display) ADD_SUBDIRECTORY(hw/external_connection) ADD_SUBDIRECTORY(hw/touchscreen) ADD_SUBDIRECTORY(hw/usb_gadget) +ADD_SUBDIRECTORY(hw/usb_client) diff --git a/hw/usb_client/CMakeLists.txt b/hw/usb_client/CMakeLists.txt new file mode 100644 index 0000000..f7b32c1 --- /dev/null +++ b/hw/usb_client/CMakeLists.txt @@ -0,0 +1,19 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(usb_client C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(usb_client_pkgs REQUIRED hwcommon dlog glib-2.0) + +FOREACH(flag ${usb_client_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE usb_client.c ../shared.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${usb_client_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/usb_client/usb_client.c b/hw/usb_client/usb_client.c new file mode 100644 index 0000000..f63354d --- /dev/null +++ b/hw/usb_client/usb_client.c @@ -0,0 +1,646 @@ +/* + * device-node + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * 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 + +#include "../shared.h" + +#include +#include +#include + +#define zalloc(amount) calloc(1, amount) + +#define MAX_GADGET_STR_LEN 256 +#define MAX_FUNCS 32 + +#define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0" + +/* Device descriptor values */ +#define LEGACY_ID_VENDOR_PATH LEGACY_ROOTPATH"/idVendor" +#define LEGACY_ID_PRODUCT_PATH LEGACY_ROOTPATH"/idProduct" +#define LEGACY_BCD_DEVICE_PATH LEGACY_ROOTPATH"/bcdDevice" +#define LEGACY_CLASS_PATH LEGACY_ROOTPATH"/bDeviceClass" +#define LEGACY_SUBCLASS_PATH LEGACY_ROOTPATH"/bDeviceSubClass" +#define LEGACY_PROTOCOL_PATH LEGACY_ROOTPATH"/bDeviceProtocol" + +/* Strings */ +#define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer" +#define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct" +#define LEGACY_ISERIAL_PATH LEGACY_ROOTPATH"/iSerial" + +/* Functions in each config */ +#define LEGACY_CONFIG_1_PATH LEGACY_ROOTPATH"/funcs_fconf" +#define LEGACY_CONFIG_2_PATH LEGACY_ROOTPATH"/funcs_sconf" +/* should be single char */ +#define LEGACY_FUNC_SEP "," + +/* ON/OFF switch */ +#define LEGACY_ENABLE_PATH LEGACY_ROOTPATH"/enable" +#define LEGACY_ENABLE "1" +#define LEGACY_DISABLE "0" + +#define LEGACY_BMATTRIBUTES ((1 << 7) | (1 << 6)) +#define LEGACY_MAX_POWER 500 + +/* +5 to be always big enough */ +#define INT_BUF_SIZE (sizeof(int)*8 + 5) + +static int get_int_from_file(char *path, int *_val) +{ + char buf[INT_BUF_SIZE]; + char *endptr; + long int val; + int ret; + + ret = sys_get_str(path, buf, sizeof(buf)); + if (ret) + return ret; + + val = strtol(buf, &endptr, 0); + if (val == LONG_MIN || val == LONG_MAX || + buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n') + || val > INT_MAX) + return -EINVAL; + + *_val = (int)val; + return 0; +} + +static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget) +{ + int val; + int ret; + /* We assume that values received from kernel will be valid */ +#define GET_VALUE_FROM_SYSFS(path, field, type) \ + do { \ + ret = get_int_from_file(path, &val); \ + if (ret) \ + return ret; \ + \ + gadget->attrs.field = (type)val; \ + } while (0) + + GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t); + GET_VALUE_FROM_SYSFS(LEGACY_SUBCLASS_PATH, bDeviceSubClass, uint8_t); + GET_VALUE_FROM_SYSFS(LEGACY_PROTOCOL_PATH, bDeviceProtocol, uint8_t); + GET_VALUE_FROM_SYSFS(LEGACY_ID_VENDOR_PATH, idVendor, uint16_t); + GET_VALUE_FROM_SYSFS(LEGACY_ID_PRODUCT_PATH, idVendor, uint16_t); + GET_VALUE_FROM_SYSFS(LEGACY_BCD_DEVICE_PATH, bcdDevice, uint16_t); +#undef GET_VALUE_FROM_SYSFS + +#define GET_STRING_FROM_SYSFS(path, field) \ + do { \ + char buf[MAX_GADGET_STR_LEN]; \ + \ + ret = sys_get_str(path, buf, sizeof(buf)); \ + if (ret) \ + goto err_##field; \ + \ + gadget->strs[0].field = strdup(buf); \ + if (!gadget->strs[0].field) { \ + ret = -ENOMEM; \ + goto err_##field; \ + } \ + } while (0) + + GET_STRING_FROM_SYSFS(LEGACY_IMANUFACTURER_PATH, manufacturer); + GET_STRING_FROM_SYSFS(LEGACY_IPRODUCT_PATH, product); + GET_STRING_FROM_SYSFS(LEGACY_ISERIAL_PATH, serial); +#undef GET_STRING_FROM_SYSFS + + return 0; + +err_serial: + free(gadget->strs[0].product); +err_product: + free(gadget->strs[0].manufacturer); +err_manufacturer: + return ret; +} + +static int legacy_find_func(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i) + if (!strcmp(name, _available_funcs[i]->name)) + return i; + + return -1; +} + +static struct usb_function *legacy_find_func_in_gadget( + struct usb_gadget *gadget, const char *name) +{ + int i; + + for (i = 0; gadget->funcs[i]; ++i) + if (!strcmp(name, gadget->funcs[i]->name)) + return gadget->funcs[i]; + return NULL; +} + +static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config) +{ + struct usb_configuration *config; + + config = zalloc(sizeof(*config)); + if (!config) + goto out; + + config->strs = calloc(1, sizeof(*config->strs)); + if (!config->strs) + goto free_config; + + config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs)); + if (!config->funcs) + goto free_strs; + + /* + * We cannot read correct values + * so assume that they are always default + */ + config->attrs.bmAttributs = LEGACY_BMATTRIBUTES; + config->attrs.MaxPower = LEGACY_MAX_POWER; + + *_config = config; + + return 0; +free_strs: + free(config->strs); +free_config: + free(config); +out: + return -ENOMEM; +} + +static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname, + struct usb_function **_func) +{ + struct usb_function *func; + int ret; + + ret = legacy_find_func(fname); + if (ret < 0) + return -ENOTSUP; + + ret = _available_funcs[ret]->clone(_available_funcs[ret], &func); + if (ret) + return ret; + + *_func = func; + return 0; +} + +static int legacy_read_config(struct usb_gadget *gadget, + char *cpath, + struct usb_configuration **_config) +{ + struct usb_configuration *config; + char buf[MAX_GADGET_STR_LEN]; + char *begin = buf; + char *fname; + char *sep = LEGACY_FUNC_SEP; + int i, f_cnt; + int f_idx; + int ret; + + ret = sys_get_str(cpath, buf, sizeof(buf)); + if (ret) + return ret; + + /* Empty */ + if (buf[0] == '\0' || buf[0] == '\n') + return 0; + + /* count number of functions in this config */ + f_cnt = 1; + for (i = 0; buf[i] != '\0'; ++i) + if (buf[i] == sep[0]) + ++f_cnt; + + ret = legacy_alloc_config(f_cnt, &config); + if (ret) + return ret; + + f_idx = 0; + for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { + struct usb_function *func; + + func = legacy_find_func_in_gadget(gadget, fname); + if (!func) { + /* new function not added yet to gadget */ + ret = legacy_alloc_new_func(gadget, fname, &func); + if (!ret) + goto free_config; + } + + config->funcs[f_idx++] = func; + } + + *_config = config; + return 0; +free_config: + free(config->strs); + free(config->funcs); + free(config); + return ret; +} + +static int legacy_get_current_gadget(struct usb_client *usb, + struct usb_gadget **_gadget) +{ + struct usb_gadget *gadget; + struct usb_gadget_strings *strs; + struct usb_configuration **configs; + struct usb_function **funcs; + int i; + int ret = -ENOMEM; + + gadget = zalloc(sizeof(*gadget)); + if (!gadget) + goto out; + + strs = calloc(2, sizeof(*strs)); + if (!strs) + goto free_gadget; + + strs[0].lang_code = 0x409; + + gadget->strs = strs; + + ret = legacy_read_gadget_attrs_strs(gadget); + if (ret) + goto free_strs; + + /* There will be no more functions than bits in int */ + funcs = calloc(MAX_FUNCS, sizeof(*funcs)); + if (!funcs) + goto free_strs_with_content; + + gadget->funcs = funcs; + + /* slp-gadget use max 2 confiuration and NULL termination */ + configs = calloc(3, sizeof(*configs)); + if (!configs) + goto free_funcs; + + gadget->configs = configs; + + ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0); + if (ret) + goto free_configs; + + ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1); + if (ret) + goto free_config_1; + + *_gadget = gadget; + return 0; + +free_config_1: + free(configs[0]->funcs); + free(configs[0]->strs); + free(configs[0]); +free_configs: + free(configs); + for (i = 0; gadget->funcs[i]; ++i) + gadget->funcs[i]->free_func(gadget->funcs[i]); +free_funcs: + free(funcs); +free_strs_with_content: + free(gadget->strs[0].manufacturer); + free(gadget->strs[0].product); + free(gadget->strs[0].serial); +free_strs: + free(gadget->strs); +free_gadget: + free(gadget); +out: + return ret; +} + +static bool legacy_is_function_supported(struct usb_client *usb, + struct usb_function *func) +{ + int ret; + + /* + * TODO + * Instead of only checking whether we know this function + * we should also parse sysfs to check if it is build into + * slp-gadget. + */ + ret = legacy_find_func(func->name); + + return ret >= 0; +} + +static bool legacy_is_gadget_supported(struct usb_client *usb, + struct usb_gadget *gadget) +{ + int i, j; + + if (!gadget || !gadget->configs || !gadget->funcs) + return false; + + /* + * TODO + * Here is a good place to ensure that serial is immutable + */ + if (gadget->strs) { + /* only strings in US_en are allowed */ + if (gadget->strs[0].lang_code != 0x409 || + gadget->strs[1].lang_code) + return false; + } + + for (j = 0; gadget->configs[j]; ++j) { + struct usb_configuration *config = gadget->configs[j]; + + if (config->strs && config->strs[0].lang_code) + return false; + + if (!config->funcs) + return false; + + for (i = 0; config->funcs[i]; ++i) + if (!legacy_is_function_supported(usb, config->funcs[i])) + return false; + } + + if (j == 0 || j > 2) + return false; + + return true; +} + +/* TODO. Maybe move this to sys ? */ +static int legacy_set_int_hex(char *path, int val) +{ + char buf[MAX_GADGET_STR_LEN]; + int r; + + if (!path) + return -EINVAL; + + snprintf(buf, sizeof(buf), "%x", val); + r = sys_set_str(path, buf); + if (r < 0) + return r; + + return 0; +} + +static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs) +{ + int ret; + + ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass); + if (ret) + return ret; + + ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass); + if (ret) + return ret; + + ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol); + if (ret) + return ret; + + ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor); + if (ret) + return ret; + + ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct); + if (ret) + return ret; + + ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice); + + return ret; +} + +static int legacy_set_gadget_strs(struct usb_gadget_strings *strs) +{ + int ret = 0; + + /* + * TODO + * Here is a good place to ensure that serial is immutable + */ + + if (strs->manufacturer) { + ret = sys_set_str(LEGACY_IMANUFACTURER_PATH, + strs->manufacturer); + if (ret) + return ret; + } + + if (strs->product) { + ret = sys_set_str(LEGACY_IPRODUCT_PATH, + strs->product); + if (ret) + return ret; + } + + if (strs->serial) { + ret = sys_set_str(LEGACY_ISERIAL_PATH, + strs->serial); + if (ret) + return ret; + } + + return ret; +} + +static int legacy_set_gadget_config(char *cpath, + struct usb_configuration *config) +{ + char buf[MAX_GADGET_STR_LEN]; + int left = sizeof(buf); + char *pos = buf; + int ret; + int i; + + if (!config) { + buf[0] = '\n'; + buf[1] = '\0'; + goto empty_config; + } + + for (i = 0; config->funcs[i]; ++i) { + ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP, + config->funcs[i]->name); + if (ret >= left) + return -EOVERFLOW; + + pos += ret; + left -= ret; + } + + /* eliminate last separator */ + *(pos - 1) = '\0'; + +empty_config: + return sys_set_str(cpath, buf); +} + +static int legacy_reconfigure_gadget(struct usb_client *usb, + struct usb_gadget *gadget) +{ + int ret; + + if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget)) + return -EINVAL; + + ret = legacy_set_gadget_attrs(&gadget->attrs); + if (ret) + return ret; + + if (gadget->strs) { + ret = legacy_set_gadget_strs(gadget->strs + 0); + if (ret) + return ret; + } + + ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]); + if (ret) + return ret; + + ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]); + + return ret; +} + +static int legacy_enable(struct usb_client *usb) +{ + return sys_set_str(LEGACY_ENABLE_PATH, + LEGACY_ENABLE); +} + +static int legacy_disable(struct usb_client *usb) +{ + return sys_set_str(LEGACY_ENABLE_PATH, + LEGACY_DISABLE); +} + +static void legacy_free_config(struct usb_configuration *config) +{ + int i; + + if (!config) + return; + + if (config->strs) { + for (i = 0; config->strs[i].lang_code; ++i) + free(config->strs[i].config_str); + + free(config->strs); + } + + /* + * Each function will be free later, + * for now we cleanup only pointers. + */ + if (config->funcs) + free(config->funcs); + + free(config); +} + +static void legacy_free_gadget(struct usb_gadget *gadget) +{ + int i; + + if (!gadget) + return; + + if (gadget->strs) { + for (i = 0; gadget->strs[i].lang_code; ++i) { + free(gadget->strs[i].manufacturer); + free(gadget->strs[i].product); + free(gadget->strs[i].serial); + } + free(gadget->strs); + } + + if (gadget->configs) { + for (i = 0; gadget->configs[i]; ++i) + legacy_free_config(gadget->configs[i]); + + free(gadget->configs); + } + + if (gadget->funcs) { + for (i = 0; gadget->funcs[i]; ++i) + gadget->funcs[i]->free_func(gadget->funcs[i]); + + free(gadget->funcs); + } +} + +static int legacy_gadget_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct usb_client *legacy; + + if (!info || !common) + return -EINVAL; + + legacy = zalloc(sizeof(*legacy)); + if (!legacy) + return -ENOMEM; + + legacy->common.info = info; + legacy->get_current_gadget = legacy_get_current_gadget; + legacy->reconfigure_gadget = legacy_reconfigure_gadget; + legacy->is_gadget_supported = legacy_is_gadget_supported; + legacy->is_function_supported = legacy_is_function_supported; + legacy->enable = legacy_enable; + legacy->disable = legacy_disable; + legacy->free_gadget = legacy_free_gadget; + + *common = &legacy->common; + return 0; +} + +static int legacy_gadget_close(struct hw_common *common) +{ + struct usb_client *legacy; + + if (!common) + return -EINVAL; + + legacy = container_of(common, struct usb_client, + common); + + free(legacy); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = USB_CLIENT_HARDWARE_DEVICE_VERSION, + .id = USB_CLIENT_HARDWARE_DEVICE_ID, + .name = "legacy-gadget", + .open = legacy_gadget_open, + .close = legacy_gadget_close, +}; -- 2.7.4 From 87d196ed887110827dbd7e078c8084703973e6ad Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 29 Sep 2016 19:09:38 +0900 Subject: [PATCH 08/11] usb client: do not set serial The serial is used to distinguish devices for testing. Thus the serial is not set. Change-Id: I49b139878c68ac8769eb7d7f5d1424145eb78dd7 Signed-off-by: taeyoung --- hw/usb_client/usb_client.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hw/usb_client/usb_client.c b/hw/usb_client/usb_client.c index f63354d..455e741 100644 --- a/hw/usb_client/usb_client.c +++ b/hw/usb_client/usb_client.c @@ -460,13 +460,6 @@ static int legacy_set_gadget_strs(struct usb_gadget_strings *strs) return ret; } - if (strs->serial) { - ret = sys_set_str(LEGACY_ISERIAL_PATH, - strs->serial); - if (ret) - return ret; - } - return ret; } -- 2.7.4 From 0c663020fc164041674d4de91a87588d796059c2 Mon Sep 17 00:00:00 2001 From: scott park Date: Wed, 26 Jul 2017 21:04:57 +0900 Subject: [PATCH 09/11] led: Add LED HAL interface for ARTIK blinkm led device This is the initial implementation of LED HAL using PIO interface. The implemeted API is set_state. Change-Id: I7d9fbaf6b990ea886fe736046686e070d761adcd Signed-off-by: scott park Signed-off-by: INSUN PYO --- CMakeLists.txt | 1 + hw/led/CMakeLists.txt | 20 ++ hw/led/led.c | 374 +++++++++++++++++++++++++++++ packaging/device-manager-plugin-artik.spec | 1 + 4 files changed, 396 insertions(+) create mode 100644 hw/led/CMakeLists.txt create mode 100644 hw/led/led.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 06d4bc9..8d5c256 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) ADD_SUBDIRECTORY(hw/battery) ADD_SUBDIRECTORY(hw/display) ADD_SUBDIRECTORY(hw/external_connection) +ADD_SUBDIRECTORY(hw/led) ADD_SUBDIRECTORY(hw/touchscreen) ADD_SUBDIRECTORY(hw/usb_gadget) ADD_SUBDIRECTORY(hw/usb_client) diff --git a/hw/led/CMakeLists.txt b/hw/led/CMakeLists.txt new file mode 100644 index 0000000..6acfd7b --- /dev/null +++ b/hw/led/CMakeLists.txt @@ -0,0 +1,20 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(led C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(led_pkgs REQUIRED hwcommon dlog glib-2.0 capi-system-peripheral-io) + +FOREACH(flag ${led_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} MODULE led.c ../shared.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${led_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}/hw COMPONENT RuntimeLibraries) diff --git a/hw/led/led.c b/hw/led/led.c new file mode 100644 index 0000000..547c894 --- /dev/null +++ b/hw/led/led.c @@ -0,0 +1,374 @@ +/* + * device-manager-plugin-artik + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include + +#include +#include "../shared.h" + +#include + +#define GET_BRIGHTNESS(val) (((val) >> 24) & 0xFF) + +#define GET_TYPE(a) (((a) >> 24) & 0xFF) +#define GET_RED_ONLY(a) ((a) & 0xFF0000) +#define GET_GREEN_ONLY(a) ((a) & 0x00FF00) +#define GET_BLUE_ONLY(a) ((a) & 0x0000FF) +#define GET_RED_BRT(a) (uint8_t)(((a) >> 16) & 0xFF) +#define GET_GREEN_BRT(a) (uint8_t)(((a) >> 8) & 0xFF) +#define GET_BLUE_BRT(a) (uint8_t)((a) & 0xFF) + +/** + * GPIO Specific + */ +#define GPIO_I2C_BUS_INDEX 1 +#define BLINKM_DEFAULT_ADDR 0x09 + +/** + * LED operation command code + * Stop script: 0x6f('o') + * Set command: 0x6e('n') + * Change address command: 0x41('A') + */ +#define SET_CMD_CODE 0x6e +#define STOP_SCRIPT_CMD 0x6f +#define CHANGE_ADDR_CMD 0x41 + +typedef enum _led_rgb_type { + LED_RED, + LED_GREEN, + LED_BLUE, +} led_rgb_type_e; + +struct gpio_rgb_play_color_info { + unsigned int color; + int time; +}; + +struct gpio_rgb_play_info { + GList *play_list; + int nr_play; + int index; + guint timer; +} play_info; + +static uint8_t off_cmd[4] = { SET_CMD_CODE, 0x00, 0x00, 0x00 }; + +static void blinkm_led_stop_script(peripheral_i2c_h handle) +{ + peripheral_i2c_write_byte(handle, STOP_SCRIPT_CMD); +} + +/** + * LED set to black + */ +static void blinkm_led_off(peripheral_i2c_h handle) +{ + peripheral_i2c_write(handle, off_cmd, sizeof(off_cmd)); +} + +static void blinkm_led_init(peripheral_i2c_h handle) +{ + blinkm_led_stop_script(handle); + blinkm_led_off(handle); +} + +static void blinkm_led_set_color(peripheral_i2c_h handle, uint8_t *pkt_data, int len) +{ + peripheral_i2c_write(handle, pkt_data, len); +} + +static int gpio_led_open_device(int device_index, peripheral_i2c_h *device_handle) +{ + int ret; + + if ((ret = peripheral_i2c_open(device_index, BLINKM_DEFAULT_ADDR, device_handle)) < PERIPHERAL_ERROR_NONE) { + _E("Failed to open I2C"); + } + return ret; +} + +static int gpio_led_close_device(peripheral_i2c_h device_handle) +{ + int ret; + + if ((ret = peripheral_i2c_close(device_handle)) < PERIPHERAL_ERROR_NONE) { + _E("Failed to close I2C"); + } + return ret; +} + +static int gpio_rgb_set_brightness(struct led_state *state) +{ + uint8_t cmd_pkt[4] = { SET_CMD_CODE, }; + peripheral_i2c_h handle; + unsigned int color; + int ret; + + if (!state) + return -EINVAL; + + color = state->color; + + cmd_pkt[1] = GET_RED_BRT(color); + cmd_pkt[2] = GET_GREEN_BRT(color); + cmd_pkt[3] = GET_BLUE_BRT(color); + + _I("COLOR(%x) r(%x), g(%x), b(%x)", color, cmd_pkt[1], cmd_pkt[2], cmd_pkt[3]); + + if ((ret = gpio_led_open_device(GPIO_I2C_BUS_INDEX, &handle)) < PERIPHERAL_ERROR_NONE) + return -EIO; + + blinkm_led_set_color(handle, cmd_pkt, sizeof(cmd_pkt)); + + if ((ret = gpio_led_close_device(handle)) < PERIPHERAL_ERROR_NONE) + return -EIO; + + return 0; +} + +/* turn off led */ +static int gpio_rgb_turn_off(struct led_state *state) +{ + struct led_state st = { LED_TYPE_MANUAL, }; + return gpio_rgb_set_brightness(&st); +} + +/* release play list */ +static void free_func(gpointer data) +{ + struct gpio_rgb_play_color_info *color = data; + free(color); +} + +static void release_play_info(void) +{ + if (play_info.play_list) { + g_list_free_full(play_info.play_list, free_func); + play_info.play_list = NULL; + } + play_info.nr_play = 0; + play_info.index = 0; + if (play_info.timer) { + g_source_remove(play_info.timer); + play_info.timer = 0; + } + + gpio_rgb_turn_off(NULL); +} + +static int gpio_rgb_init_led() +{ + peripheral_i2c_h handle; + int ret; + + if ((ret = gpio_led_open_device(GPIO_I2C_BUS_INDEX, &handle)) < PERIPHERAL_ERROR_NONE) + return ret; + + blinkm_led_init(handle); + + if ((ret = gpio_led_close_device(handle)) < PERIPHERAL_ERROR_NONE) + return ret; + + return ret; +} + +/* timer callback to change colors which are stored in play_list */ +static gboolean gpio_rgb_timer_expired(gpointer data) +{ + struct gpio_rgb_play_color_info *color; + struct led_state state = {LED_TYPE_MANUAL, }; + int ret; + + if (play_info.timer) { + g_source_remove(play_info.timer); + play_info.timer = 0; + } + + color = g_list_nth_data(play_info.play_list, play_info.index); + if (!color) { + _E("Failed to get (%d)th item from the play list", play_info.index); + goto out; + } + + play_info.timer = g_timeout_add(color->time, gpio_rgb_timer_expired, data); + if (play_info.timer == 0) { + _E("Failed to add timeout for LED blinking"); + goto out; + } + + state.color = color->color; + + ret = gpio_rgb_set_brightness(&state); + if (ret < 0) { + _E("Failed to set brightness (%d)", ret); + goto out; + } + + play_info.index++; + if (play_info.index == play_info.nr_play) + play_info.index = 0; + + return G_SOURCE_CONTINUE; + +out: + release_play_info(); + + return G_SOURCE_REMOVE; +} + +/* insert color info to the play_list */ +static int gpio_rgb_insert_play_list(unsigned color, int on, int off) +{ + struct gpio_rgb_play_color_info *on_info, *off_info; + + if (color == 0) + return -EINVAL; + on_info = calloc(1, sizeof(struct gpio_rgb_play_color_info)); + if (!on_info) + return -ENOMEM; + off_info = calloc(1, sizeof(struct gpio_rgb_play_color_info)); + if (!off_info) { + free(on_info); + return -ENOMEM; + } + + on_info->color = color; + on_info->time = on; + play_info.play_list = g_list_append(play_info.play_list, on_info); + + off_info->color = 0; + off_info->time = off; + play_info.play_list = g_list_append(play_info.play_list, off_info); + + return 0; +} + +/* insert color info to the play list and start to play */ +static int gpio_rgb_set_brightness_blink(struct led_state *state) +{ + unsigned int val; + int ret; + + val = GET_RED_ONLY(state->color); + if (val) { + ret = gpio_rgb_insert_play_list(val, state->duty_on, state->duty_off); + if (ret < 0) + _E("Failed to insert color info to list (%d)", ret); + } + val = GET_GREEN_ONLY(state->color); + if (val) { + ret = gpio_rgb_insert_play_list(val, state->duty_on, state->duty_off); + if (ret < 0) + _E("Failed to insert color info to list (%d)", ret); + } + val = GET_BLUE_ONLY(state->color); + if (val) { + ret = gpio_rgb_insert_play_list(val, state->duty_on, state->duty_off); + if (ret < 0) + _E("Failed to insert color info to list (%d)", ret); + } + + play_info.nr_play = g_list_length(play_info.play_list); + play_info.index = 0; + + gpio_rgb_timer_expired(NULL); + return 0; +} + +static int gpio_rgb_turn_on(struct led_state *state) +{ + if (state->type == LED_TYPE_MANUAL) + return gpio_rgb_set_brightness(state); + + return gpio_rgb_set_brightness_blink(state); +} + +static int gpio_rgb_set_state(struct led_state *state) +{ + if (!state) + return -EINVAL; + + switch (state->type) { + case LED_TYPE_BLINK: + case LED_TYPE_MANUAL: + break; + default: + _E("Not suppoted type (%d)", state->type); + return -ENOTSUP; + } + release_play_info(); + + if (GET_TYPE(state->color) == 0) + return gpio_rgb_turn_off(state); + + return gpio_rgb_turn_on(state); +} + +static int led_open(struct hw_info *info, + const char *id, struct hw_common **common) +{ + struct led_device *led_dev; + size_t len; + + if (!info || !id || !common) + return -EINVAL; + + led_dev = calloc(1, sizeof(struct led_device)); + if (!led_dev) + return -ENOMEM; + + led_dev->common.info = info; + + len = strlen(id) + 1; + if (!strncmp(id, LED_ID_NOTIFICATION, len)) { + if (gpio_rgb_init_led()) { + free(led_dev); + return -EIO; + } else + led_dev->set_state = gpio_rgb_set_state; + + } else { + free(led_dev); + return -ENOTSUP; + } + + *common = (struct hw_common *)led_dev; + return 0; +} + +static int led_close(struct hw_common *common) +{ + if (!common) + return -EINVAL; + + free(common); + return 0; +} + +HARDWARE_MODULE_STRUCTURE = { + .magic = HARDWARE_INFO_TAG, + .hal_version = HARDWARE_INFO_VERSION, + .device_version = LED_HARDWARE_DEVICE_VERSION, + .id = LED_HARDWARE_DEVICE_ID, + .name = "I2C RGB LED", + .open = led_open, + .close = led_close, +}; diff --git a/packaging/device-manager-plugin-artik.spec b/packaging/device-manager-plugin-artik.spec index 8b2db3a..dda9808 100755 --- a/packaging/device-manager-plugin-artik.spec +++ b/packaging/device-manager-plugin-artik.spec @@ -13,6 +13,7 @@ BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(hwcommon) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libudev) +BuildRequires: pkgconfig(capi-system-peripheral-io) %description Device manager plugin artik -- 2.7.4 From ec8c73e41a57a6b519c730ec3461d83a2363be7e Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Mon, 11 Sep 2017 13:21:42 +0900 Subject: [PATCH 10/11] remove build warning Touchscreen_init calls the open function of hal at the beginning of the boot with the call stack below. So the open function of hal is never called at the same time in multi-thread. Therefore, we can use safely readdir in deviced. 0 touchscreen_init 1 0x2a00b02c in devices_init (data=0x0) at /usr/src/debug/deviced-2.0.0/src/core/devices.c:102 2 0x2a00e424 in deviced_main (argc=, argv=) at /usr/src/debug/deviced-2.0.0/src/core/main.c:93 3 0x2a0078f4 in main (argc=1, argv=0xbefffe64) at /usr/src/debug/deviced-2.0.0/src/core/main.c:123 Signed-off-by: INSUN PYO Change-Id: Ieb4ded94379c01592cabd85a5ed6eb525042bc97 (cherry picked from commit 4a8b1ec8da47eb05d58d1b67fcb678cc7755d27e) --- hw/touchscreen/touchscreen.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/touchscreen/touchscreen.c b/hw/touchscreen/touchscreen.c index 1d5be64..fe3c97e 100755 --- a/hw/touchscreen/touchscreen.c +++ b/hw/touchscreen/touchscreen.c @@ -40,7 +40,6 @@ static char *touchscreen_node; static int touchscreen_probe(void) { DIR *d; - struct dirent entry; struct dirent *dir; char buf[PATH_MAX]; int val, ret = -ENOTSUP; @@ -49,7 +48,7 @@ static int touchscreen_probe(void) if (!d) return -errno; - while (readdir_r(d, &entry, &dir) == 0 && dir != NULL) { + while ((dir = readdir(d))) { if (dir->d_name[0] == '.') continue; snprintf(buf, sizeof(buf), "%s%s%s", INPUT_PATH, -- 2.7.4 From fb08937c04cea47e3a0742a1f941763b359bd479 Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Tue, 12 Sep 2017 10:53:29 +0900 Subject: [PATCH 11/11] Modification of coding rule violation Signed-off-by: INSUN PYO Change-Id: I21e21fb7444722f7559b3dc8de7b2540e00e7ef8 (cherry picked from commit b688a4a641f3d0582cd9a9ffd0bf66254fbf3294) --- hw/battery/battery.c | 2 +- hw/usb_client/usb_client.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/battery/battery.c b/hw/battery/battery.c index 6baf474..076a542 100755 --- a/hw/battery/battery.c +++ b/hw/battery/battery.c @@ -57,7 +57,7 @@ static void remove_not_string(char *str) { char *t = str; - while(*t != '\0') { + while (*t != '\0') { if (*t == '\r' || *t == '\n' || *t == '\x0a') diff --git a/hw/usb_client/usb_client.c b/hw/usb_client/usb_client.c index 455e741..2716eea 100644 --- a/hw/usb_client/usb_client.c +++ b/hw/usb_client/usb_client.c @@ -172,7 +172,7 @@ static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config) if (!config->funcs) goto free_strs; - /* + /* * We cannot read correct values * so assume that they are always default */ @@ -444,7 +444,7 @@ static int legacy_set_gadget_strs(struct usb_gadget_strings *strs) /* * TODO * Here is a good place to ensure that serial is immutable - */ + */ if (strs->manufacturer) { ret = sys_set_str(LEGACY_IMANUFACTURER_PATH, @@ -531,7 +531,7 @@ static int legacy_enable(struct usb_client *usb) static int legacy_disable(struct usb_client *usb) { return sys_set_str(LEGACY_ENABLE_PATH, - LEGACY_DISABLE); + LEGACY_DISABLE); } static void legacy_free_config(struct usb_configuration *config) -- 2.7.4