Add USB gadget HAL implementation 12/86012/4
authortaeyoung <ty317.kim@samsung.com>
Fri, 9 Sep 2016 11:27:41 +0000 (20:27 +0900)
committertaeyoung <ty317.kim@samsung.com>
Tue, 27 Sep 2016 04:38:47 +0000 (13:38 +0900)
USB gadget HAL is an abstraction layer which translates
set of functions into full USB gadget description specific
for this particular device.

Change-Id: I9920a8e400aa3c16df9a650e7611d9eb920ae623
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: taeyoung <ty317.kim@samsung.com>
CMakeLists.txt
hw/shared.c [new file with mode: 0644]
hw/shared.h [new file with mode: 0644]
hw/usb_gadget/CMakeLists.txt [new file with mode: 0644]
hw/usb_gadget/usb_gadget.c [new file with mode: 0644]
packaging/device-manager-plugin-odroid.changes [deleted file]
packaging/device-manager-plugin-odroid.manifest [moved from device-manager-plugin-odroid.manifest with 100% similarity]
packaging/device-manager-plugin-odroid.spec

index 264036c..86fbb1e 100644 (file)
@@ -1,5 +1,11 @@
-cmake_minimum_required(VERSION 2.8)
-project(slp_devman_plugin)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(device-manager-odroid C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+ADD_SUBDIRECTORY(hw/usb_gadget)
+
+SET(PROJ_NAME slp_devman_plugin)
 
 set(SRCS
   src/device_manager_plugin_odroid.c
@@ -10,6 +16,6 @@ pkg_check_modules(pkgs REQUIRED devman_plugin)
 
 include_directories(${pkgs_INCLUDE_DIRS})
 
-add_library(${PROJECT_NAME} SHARED ${SRCS})
-target_link_libraries(${PROJECT_NAME} ${pkgs_LIBRARIES})
-install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
+add_library(${PROJ_NAME} SHARED ${SRCS})
+target_link_libraries(${PROJ_NAME} ${pkgs_LIBRARIES})
+install(TARGETS ${PROJ_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
diff --git a/hw/shared.c b/hw/shared.c
new file mode 100644 (file)
index 0000000..b6401c1
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#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 100644 (file)
index 0000000..da51ca4
--- /dev/null
@@ -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 <dlog.h>
+#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/usb_gadget/CMakeLists.txt b/hw/usb_gadget/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2e28b15
--- /dev/null
@@ -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 (file)
index 0000000..0bcb10b
--- /dev/null
@@ -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 <hw/usb_gadget.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#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
diff --git a/packaging/device-manager-plugin-odroid.changes b/packaging/device-manager-plugin-odroid.changes
deleted file mode 100644 (file)
index 2223d47..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-* Fri Jun 27 2014 Ćukasz Stelmach <l.stelmach@samsung.com> 6373e7e1
-- Initial release
index b824f1e..7a220c7 100644 (file)
@@ -5,23 +5,36 @@ 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(devman_plugin)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(hwcommon)
+BuildRequires:  pkgconfig(glib-2.0)
 
 %description
-Tizen OEM Adaptation Layer library for ODROID development board.
+Device manager plugin for ODROID development board.
 
 %prep
 %setup -q
+cp %{SOURCE1} .
 
 %build
-%cmake .
+%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
 make %{?jobs:-j%jobs}
 
 %install
 %make_install
 
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
 %files
+%{_libdir}/hw/*.so
+%manifest %{name}.manifest
 %license LICENSE
-%manifest device-manager-plugin-odroid.manifest
 %{_libdir}/libslp_devman_plugin.so