From 6393c2294526d60995c1f87b22f469fdbf717035 Mon Sep 17 00:00:00 2001 From: "wansu.yoo" Date: Fri, 17 Jun 2016 18:07:51 +0900 Subject: [PATCH 2/8] 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 3/8] 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 4/8] 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 5/8] 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 6/8] 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 7/8] 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 8/8] 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