summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortaeyoung <ty317.kim@samsung.com>2016-09-09 20:27:41 +0900
committerTaeyoung Kim <ty317.kim@samsung.com>2016-09-23 01:55:35 -0700
commit591890fa032a9ddde1d5b1d22f1f8625170e4264 (patch)
tree61d764c236c6e95310003308045beda4059e0175
parentdddebdc205c3499c325e6db79a5a19a8e6c19566 (diff)
downloaddevice-manager-plugin-artik-591890fa032a9ddde1d5b1d22f1f8625170e4264.tar.gz
device-manager-plugin-artik-591890fa032a9ddde1d5b1d22f1f8625170e4264.tar.bz2
device-manager-plugin-artik-591890fa032a9ddde1d5b1d22f1f8625170e4264.zip
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 <k.opasiak@samsung.com>
-rwxr-xr-xCMakeLists.txt3
-rw-r--r--hw/usb_gadget/CMakeLists.txt19
-rw-r--r--hw/usb_gadget/usb_gadget.c392
3 files changed, 413 insertions, 1 deletions
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 <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