diff options
author | Paweł Szewczyk <p.szewczyk@samsung.com> | 2018-06-25 14:43:03 +0200 |
---|---|---|
committer | Paweł Szewczyk <p.szewczyk@samsung.com> | 2018-06-26 15:40:14 +0200 |
commit | 441caf215fa4b0419a80780474ee7b66569fd775 (patch) | |
tree | 9d3feba96c0a04b51b31e7b887a20e8406003372 /hw | |
parent | 5baef35afbf4d869e14c177237536ff5ed61c390 (diff) | |
download | libdevice-node-441caf215fa4b0419a80780474ee7b66569fd775.tar.gz libdevice-node-441caf215fa4b0419a80780474ee7b66569fd775.tar.bz2 libdevice-node-441caf215fa4b0419a80780474ee7b66569fd775.zip |
Move usb_gadget common code from device-manager-pluginssubmit/tizen/20180628.074924
Change-Id: I19f45a7f858bd09f4e2403e4227a7c2a71aab05a
Signed-off-by: Paweł Szewczyk <p.szewczyk@samsung.com>
Diffstat (limited to 'hw')
-rwxr-xr-x | hw/usb_gadget.h | 4 | ||||
-rw-r--r-- | hw/usb_gadget_common.c | 425 |
2 files changed, 429 insertions, 0 deletions
diff --git a/hw/usb_gadget.h b/hw/usb_gadget.h index 4c49e70..31e1a91 100755 --- a/hw/usb_gadget.h +++ b/hw/usb_gadget.h @@ -290,4 +290,8 @@ struct usb_gadget_translator { void (*cleanup_gadget)(struct usb_gadget *gadget); }; +int simple_translator_open(struct hw_info *info, + const char *id, struct hw_common **common); +int simple_translator_close(struct hw_common *common); + #endif diff --git a/hw/usb_gadget_common.c b/hw/usb_gadget_common.c new file mode 100644 index 0000000..e76326d --- /dev/null +++ b/hw/usb_gadget_common.c @@ -0,0 +1,425 @@ +/* + * libdevice-node + * + * Copyright (c) 2018 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 <hw/usb_gadget.h> +#include <hw/board.h> + +#include <stdio.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 0x0100 + +#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 + +#ifndef EXPORT +#define EXPORT __attribute__ ((visibility("default"))) +#endif + +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 get_device_serial(char **out) +{ + struct hw_info *info; + struct hw_common *common; + struct hw_board *board; + int ret; + + if (hw_get_info(BOARD_HARDWARE_DEVICE_ID, (const struct hw_info **)&info)) + return -ENOENT; + + ret = info->open(info, NULL, &common); + if (ret < 0) + return ret; + + board = container_of(common, struct hw_board, common); + return board->get_device_serial(out); +} + +static int alloc_default_gadget(struct usb_gadget **_gadget) +{ + struct usb_gadget *gadget; + struct usb_gadget_strings *strs; + struct usb_configuration **configs; + int ret; + + 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); + ret = get_device_serial(&strs[0].serial); + if (ret < 0) + 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 = 0; + /* 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_ACM | USB_FUNCTION_SDB: + n_configs = 1; + functions[0][0] = USB_FUNCTION_ACM; + functions[0][1] = USB_FUNCTION_SDB; + functions[0][2] = 0; + gadget->attrs.idProduct = 0x6860; + 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_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; + +#if 0 + 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 | 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; +#endif + }; + + if (n_configs > 2 || n_configs <= 0) { + 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; +} + +EXPORT +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; +} + +EXPORT +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; +} |