From 4f76e2b02b536704479168e7c8d68b02c671b857 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Wed, 6 Apr 2022 01:40:04 -0700 Subject: [PATCH] usb: move usb-gadget from device-common to deviced Change-Id: I3190fb3c7ff62aab41dc3f4959d26ce8647d03bc Signed-off-by: Youngjae Cho --- src/usb/usb-dbus.c | 1 - src/usb/usb-debug.c | 1 - src/usb/usb-gadget-cfs-gadget.c | 645 +++++++++++++++++++++++++++++++++++++ src/usb/usb-gadget-legacy-gadget.c | 358 ++++++++++++++++++++ src/usb/usb-gadget.c | 465 ++++++++++++++++++++++++++ src/usb/usb-gadget.h | 101 ++++++ src/usb/usb-state.c | 2 +- src/usb/usb-tethering.c | 1 - src/usb/usb.c | 16 +- 9 files changed, 1578 insertions(+), 12 deletions(-) create mode 100644 src/usb/usb-gadget-cfs-gadget.c create mode 100644 src/usb/usb-gadget-legacy-gadget.c create mode 100644 src/usb/usb-gadget.c create mode 100644 src/usb/usb-gadget.h diff --git a/src/usb/usb-dbus.c b/src/usb/usb-dbus.c index 700c86d..137a5e1 100644 --- a/src/usb/usb-dbus.c +++ b/src/usb/usb-dbus.c @@ -21,7 +21,6 @@ #include #include -#include #include "core/log.h" diff --git a/src/usb/usb-debug.c b/src/usb/usb-debug.c index 3f138d4..f6bfb23 100644 --- a/src/usb/usb-debug.c +++ b/src/usb/usb-debug.c @@ -21,7 +21,6 @@ #include #include -#include #include "core/log.h" #include "shared/device-notifier.h" diff --git a/src/usb/usb-gadget-cfs-gadget.c b/src/usb/usb-gadget-cfs-gadget.c new file mode 100644 index 0000000..61583e0 --- /dev/null +++ b/src/usb/usb-gadget-cfs-gadget.c @@ -0,0 +1,645 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include "usb-gadget.h" + +#define CONFIGFS_PATH "/sys/kernel/config" + +#define CONFIGFS_GADGET_NAME "hal-gadget" +#define CONFIGFS_CONFIG_LABEL "hal-config" + +#define NAME_INSTANCE_SEP '.' +#define MAX_INSTANCE_LEN 512 + +#define USB_FUNCS_PATH "/dev/usb-funcs" + +enum cfs_function_service_operation { + CFS_FUNCTION_SERVICE_START, + CFS_FUNCTION_SERVICE_STOP, + CFS_FUNCTION_SERVICE_POST_STOP, +}; + +struct cfs_client { + usbg_state *ctx; + usbg_gadget *gadget; + usbg_udc *udc; +}; + +/* Based on values in slp-gadget kernel module */ +struct usbg_gadget_attrs default_g_attrs = { + .idVendor = DEFAULT_VID, + .idProduct = DEFAULT_PID, + .bcdDevice = DEFAULT_BCD_DEVICE, +}; + +struct usbg_gadget_strs default_g_strs = { + .manufacturer = DEFAULT_MANUFACTURER, + .product = DEFAULT_PRODUCT, + .serial = DEFAULT_SERIAL, +}; + +struct cfs_client *g_cfs_client; + +static struct usb_function *cfs_find_usb_function(usbg_function *function) +{ + char *sep; + char buf[MAX_INSTANCE_LEN]; + const char *instance = usbg_get_function_instance(function); + const char *name = usbg_get_function_type_str(usbg_get_function_type(function)); + + /* Ex. name:"ffs", instance: "sdb.default" */ + if (strcmp(name, usbg_get_function_type_str(USBG_F_FFS)) == 0) { + strncpy(buf, instance, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + /* Ex. "sdb.default" ==> "sdb" + "default" */ + sep = strchr(buf, NAME_INSTANCE_SEP); + if (!sep || !sep[1]) + return NULL; + *sep = '\0'; + + name = buf; + instance = sep + 1; + } + + return find_usb_function_by_name_instance(name, instance); +} + +static bool cfs_is_function_supported(struct usb_function *func) +{ + char buf[PATH_MAX]; + + if (func->is_functionfs) { + /* functionfs must have a service */ + if (!func->service) + return false; + + snprintf(buf, sizeof(buf), "/usr/lib/systemd/system/%s.socket", func->service); + if (access(buf, F_OK)) + return false; + } else { + if (usbg_lookup_function_type(func->name) < 0) + return false; + } + + return true; +} + +static bool cfs_is_gadget_supported(struct usb_gadget *gadget) +{ + int i, j; + struct usb_configuration *config; + + if (!gadget || !gadget->configs || !gadget->configs[0] || !gadget->configs[0]->funcs[0]) + return false; + + if (!gadget->attrs.idVendor || !gadget->attrs.idProduct || !gadget->attrs.bcdDevice) + return false; + + /* only strings in US_en are allowed */ + if (gadget->strs.lang_code != DEFAULT_LANG) + return false; + + if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial) + return false; + + for (j = 0; gadget->configs[j]; ++j) { + config = gadget->configs[j]; + + if (!config->funcs) + return false; + + for (i = 0; config->funcs[i]; ++i) + if (!cfs_is_function_supported(config->funcs[i])) + return false; + } + + return true; +} + +static int cfs_set_gadget_attrs(struct cfs_client *cfs_client, + struct usb_gadget_attrs *attrs) +{ + int ret; + struct usbg_gadget_attrs gadget_attrs; + + ret = usbg_get_gadget_attrs(cfs_client->gadget, &gadget_attrs); + if (ret) + return ret; + + gadget_attrs.bDeviceClass = attrs->bDeviceClass; + gadget_attrs.bDeviceSubClass = attrs->bDeviceSubClass; + gadget_attrs.bDeviceProtocol = attrs->bDeviceProtocol; + gadget_attrs.idVendor = attrs->idVendor; + gadget_attrs.idProduct = attrs->idProduct; + gadget_attrs.bcdDevice = attrs->bcdDevice; + + ret = usbg_set_gadget_attrs(cfs_client->gadget, &gadget_attrs); + + return ret; +} + +static int cfs_set_gadget_strs(struct cfs_client *cfs_client, struct usb_gadget_strings *strs) +{ + int ret; + + if (!strs->manufacturer || !strs->product || !strs->serial) + return -EINVAL; + + ret = usbg_set_gadget_str(cfs_client->gadget, USBG_STR_MANUFACTURER, strs->lang_code, strs->manufacturer); + if (ret) + return ret; + + ret = usbg_set_gadget_str(cfs_client->gadget, USBG_STR_PRODUCT, strs->lang_code, strs->product); + if (ret) + return ret; + + ret = usbg_set_gadget_str(cfs_client->gadget, USBG_STR_SERIAL_NUMBER, strs->lang_code, strs->serial); + if (ret) + return ret; + + return 0; +} + +static int cfs_ensure_dir(char *path) +{ + if (mkdir(path, 0770) < 0) + return (errno == EEXIST) ? 0 : -errno; + + return 0; +} + + +static int cfs_prep_ffs_service(struct usb_function *usb_func, usbg_function *function) +{ + int ret; + const char *name; + const char *service; + const char *instance; + const char *dev_name; + char buf[MAX_INSTANCE_LEN]; + + if (!usb_func || !function) + return -EINVAL; + + if (usbg_get_function_type(function) != USBG_F_FFS) + return -EINVAL; + + name = usb_func->name; + service = usb_func->service; + instance = usb_func->instance; + dev_name = usbg_get_function_instance(function); + + /* "/dev/usb-funcs" + "/" + "sdb" + "/" + "default" + '0' */ + if (strlen(USB_FUNCS_PATH) + strlen(name) + strlen(instance) + 3 > sizeof(buf)) + return -ENAMETOOLONG; + + /* mkdir /dev/usb-funcs */ + ret = cfs_ensure_dir(USB_FUNCS_PATH); + if (ret < 0) + return ret; + + /* mkdir /dev/usb-funcs/sdb */ + snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, name); + ret = cfs_ensure_dir(buf); + if (ret < 0) + goto out_rmdir; + + /* mkdir /dev/usb-funcs/sdb/default */ + snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, name, instance); + ret = cfs_ensure_dir(buf); + if (ret < 0) + goto out_rmdir; + + /* mount -t functionfs sdb.default /dev/usb-funcs/sdb/default */ + ret = mount(dev_name, buf, "functionfs", 0, NULL); + if (ret < 0) + goto out_rmdir; + + /* start sdbd.socket */ + ret = systemd_start_unit_wait_started(service, ".socket", -1); + if (ret < 0) + goto out_unmount; + + return 0; + +out_unmount: + umount(buf); + +out_rmdir: + snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, name, instance); + rmdir(buf); + + snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, name); + rmdir(buf); + + rmdir(USB_FUNCS_PATH); + + return ret; +} + +static int cfs_cleanup_ffs_service(usbg_function *function) +{ + int ret; + char buf[MAX_INSTANCE_LEN]; + struct usb_function *usb_function; + + if (!function) + return -EINVAL; + + usb_function = cfs_find_usb_function(function); + if (!usb_function) + return -ENOENT; + + /* stop .socket first and stop .service later becuase of socket activation */ + if (usb_function->service) { + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".socket", -1); + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); + } + + /* umount /dev/usb-funcs/[sdb|mtp]/default and remove it's directory */ + ret = snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, usb_function->name, usb_function->instance); + if (ret < 0) + return ret; + + ret = umount(buf); + if (ret < 0) + return ret; + + ret = rmdir(buf); + if (ret < 0) + return ret; + + /* remove /dev/usb-funcs/[sdb|mtp] directory */ + ret = snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, usb_function->name); + if (ret < 0) + return ret; + + ret = rmdir(buf); + if (ret < 0 && errno != ENOTEMPTY) + return ret; + + /* remove /dev/usb-funcs/ directory */ + ret = rmdir(USB_FUNCS_PATH); + if (ret < 0 && errno != ENOTEMPTY) + return ret; + + return 0; +} + + +static int cfs_set_rndis_mac_addr(usbg_gadget *gadget, usbg_function *func) +{ + int i, ret; + struct ether_addr ethaddr; + struct usbg_gadget_strs strs; + struct usbg_f_net *nf = usbg_to_net_function(func); + + if (!nf) + return -EINVAL; + + ret = usbg_get_gadget_strs(gadget, LANG_US_ENG, &strs); + if (ret != USBG_SUCCESS) + return ret; + + for (i = 0; i < ETHER_ADDR_LEN; i++) + ethaddr.ether_addr_octet[i] = 0; + + for (i = 0; (i < 256) && strs.serial[i]; i++) { + ethaddr.ether_addr_octet[i % (ETHER_ADDR_LEN - 1) + 1] ^= strs.serial[i]; + } + ethaddr.ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ + ethaddr.ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */ + + usbg_free_gadget_strs(&strs); + + /* host_addr changes mac address */ + ret = usbg_f_net_set_host_addr(nf, ðaddr); + + return ret; +} + +static int cfs_cleanup_all_config_and_function(struct cfs_client *cfs_client) +{ + int ret; + usbg_config *config; + usbg_function *function; + + /* delete all configs */ +restart_rm_config: + usbg_for_each_config(config, cfs_client->gadget) { + ret = usbg_rm_config(config, USBG_RM_RECURSE); + if (ret) + return ret; + + goto restart_rm_config; /* You cannot delete a config directly in an iterator. */ + } + + /* delete all functions */ +restart_rm_function: + usbg_for_each_function(function, cfs_client->gadget) { + if (usbg_get_function_type(function) == USBG_F_FFS) { + ret = cfs_cleanup_ffs_service(function); + if (ret) + return ret; + } + + ret = usbg_rm_function(function, USBG_RM_RECURSE); + if (ret) + return ret; + + goto restart_rm_function; /* You cannot delete a function directly in an iterator. */ + } + + return 0; +} + +static int cfs_set_gadget_config(struct cfs_client *cfs_client, int config_id, struct usb_configuration *usb_config) +{ + int i; + int ret; + int function_type; + usbg_config *config; + usbg_function *function; + struct usb_function *usb_func; + char instance[MAX_INSTANCE_LEN]; + struct usbg_config_attrs cattrs = { + .bmAttributes = usb_config->attrs.bmAttributs, + .bMaxPower = usb_config->attrs.MaxPower/2, + }; + + if (!usb_config->funcs || !usb_config->funcs[0]) + return -EINVAL; + + ret = usbg_create_config(cfs_client->gadget, config_id, CONFIGFS_CONFIG_LABEL, &cattrs, NULL, &config); + if (ret) + return ret; + + if (usb_config->strs.config_str) { + ret = usbg_set_config_string(config, usb_config->strs.lang_code, usb_config->strs.config_str); + if (ret) + return ret; + } + + for (i = 0; usb_config->funcs[i]; ++i) { + usb_func = usb_config->funcs[i]; + + /* name("sdb") + NAME_INSTANCE_SEP(".") + instance("default") + '\0' */ + if (strlen(usb_func->name) + strlen(usb_func->instance) + 2 > sizeof(instance)) + return -ENAMETOOLONG; + + /* In functionfs, the instance is used in the format "[sdb|mtp].default" instead of "default" */ + if (usb_func->is_functionfs) { + function_type = USBG_F_FFS; + snprintf(instance, sizeof(instance), "%s%c%s", usb_func->name, NAME_INSTANCE_SEP, usb_func->instance); + } else { + function_type = usbg_lookup_function_type(usb_func->name); + strncpy(instance, usb_func->instance, sizeof(instance) - 1); + instance[sizeof(instance) - 1] = '\0'; + } + + function = usbg_get_function(cfs_client->gadget, function_type, instance); + if (!function) { + ret = usbg_create_function(cfs_client->gadget, function_type, instance, NULL, &function); + if (ret) + return ret; + + /* Setting rndis mac address. This should be done at this point, + * since the node host_addr changes to read only after the function + * is added to config. */ + if (usbg_get_function_type(function) == USBG_F_RNDIS) + (void)cfs_set_rndis_mac_addr(cfs_client->gadget, function); /* A random value is used if fails */ + + if (usbg_get_function_type(function) == USBG_F_FFS) { + ret = cfs_prep_ffs_service(usb_func, function); + if (ret) + return ret; + } + } + + ret = usbg_add_config_function(config, NULL, function); + if (ret) + return ret; + } + + return 0; +} + +static void cfs_start_stop_service_and_handler(usbg_gadget *gadget, enum cfs_function_service_operation operation) +{ + usbg_function *function; + struct usb_function *usb_function; + + usbg_for_each_function(function, gadget) { + usb_function = cfs_find_usb_function(function); + if (!usb_function) + continue; + + switch(operation) { + case CFS_FUNCTION_SERVICE_START: + if (usb_function->handler) + usb_function->handler(1); + + /* functionfs service is automatically started by socket activation */ + if (!usb_function->is_functionfs && usb_function->service) + (void)systemd_start_unit_wait_started(usb_function->service, ".service", -1); + break; + + case CFS_FUNCTION_SERVICE_STOP: + if (!usb_function->is_functionfs && usb_function->service && !usb_function->remain_after_disable) + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); + + if (usb_function->handler) + usb_function->handler(0); + break; + + case CFS_FUNCTION_SERVICE_POST_STOP: + if (usb_function->is_functionfs && usb_function->service && !usb_function->remain_after_disable) + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); + break; + + default: + break; + } + } +} + +static int usb_gadget_cfs_enable(void) +{ + int ret; + + if (!g_cfs_client) + return -EINVAL; + + ret = usbg_enable_gadget(g_cfs_client->gadget, g_cfs_client->udc); + if (ret) + return ret; + + cfs_start_stop_service_and_handler(g_cfs_client->gadget, CFS_FUNCTION_SERVICE_START); + + return 0; +} + +static int usb_gadget_cfs_disable(void) +{ + int ret; + + if (!g_cfs_client) + return -EINVAL; + + cfs_start_stop_service_and_handler(g_cfs_client->gadget, CFS_FUNCTION_SERVICE_STOP); + + ret = usbg_disable_gadget(g_cfs_client->gadget); /* ignore error checking */ + + /* + * Since functionfs service works with socket activation, you must stop it after disabling gadget. + * If usb data may come in after stopping functionfs service and before disabling gadget, + * functionfs service wakes up again by socket activation. + */ + cfs_start_stop_service_and_handler(g_cfs_client->gadget, CFS_FUNCTION_SERVICE_POST_STOP); + + return ret; +} + +static int usb_gadget_cfs_reconfigure_gadget(struct usb_gadget *gadget) +{ + int i; + int ret; + + if (!g_cfs_client || !gadget) + return -EINVAL; + + /* Verify the gadget and check if function is supported */ + if (!cfs_is_gadget_supported(gadget)) + return -ENOTSUP; + + ret = cfs_set_gadget_attrs(g_cfs_client, &gadget->attrs); + if (ret) + return ret; + + ret = cfs_set_gadget_strs(g_cfs_client, &gadget->strs); + if (ret) + return ret; + + ret = cfs_cleanup_all_config_and_function(g_cfs_client); + if (ret) + return ret; + + for (i = 0; gadget->configs[i]; ++i) { + ret = cfs_set_gadget_config(g_cfs_client, i + 1, gadget->configs[i]); + if (ret) + return ret; + } + + return 0; +} + +static int usb_gadget_cfs_open(void) +{ + int ret; + + g_cfs_client = calloc(1, sizeof(*g_cfs_client)); + if (!g_cfs_client) + return -ENOMEM; + + ret = usbg_init(CONFIGFS_PATH, &g_cfs_client->ctx); + if (ret) + goto err_usbg_init; + + g_cfs_client->udc = usbg_get_first_udc(g_cfs_client->ctx); + if (!g_cfs_client->udc) { + ret = -ENODEV; + goto err_no_udc; + } + + ret = usbg_create_gadget(g_cfs_client->ctx, CONFIGFS_GADGET_NAME, + &default_g_attrs, &default_g_strs, &g_cfs_client->gadget); + if (ret) + goto err_create_gadget; + + return 0; + +err_create_gadget: +err_no_udc: + usbg_cleanup(g_cfs_client->ctx); +err_usbg_init: + free(g_cfs_client); + + return ret; +} + +static int usb_gadget_cfs_close(void) +{ + usbg_function *function; + struct usb_function *usb_func; + + if (!g_cfs_client) + return -EINVAL; + + usbg_for_each_function(function, g_cfs_client->gadget) { + usb_func = cfs_find_usb_function(function); + if (!usb_func) + continue; + + if (usb_func->is_functionfs && usb_func->service) { + (void)systemd_stop_unit_wait_stopped(usb_func->service, ".socket", -1); + (void)systemd_stop_unit_wait_stopped(usb_func->service, ".service", -1); + } + } + + /* + * For now we don't check for errors + * but we should somehow handle them + */ + usbg_rm_gadget(g_cfs_client->gadget, USBG_RM_RECURSE); + usbg_cleanup(g_cfs_client->ctx); + free(g_cfs_client); + + return 0; +} + +int usb_gadget_cfs_supported(void) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + int configfs = 0; + + fp = fopen("/proc/filesystems", "r"); + if (!fp) + return 0; + + while (getline(&line, &len, fp) != -1) { + if (strstr(line, "configfs")) + configfs = 1; + } + + fclose(fp); + free(line); + + if (configfs) + CRITICAL_LOG("Usb-gadget is supported via configfs."); + + return configfs; +} + +void usb_gadget_bind_cfs_gadget(int (**open) (void), int (**close) (void), int (**enable) (void), + int (**disable) (void), int (**reconfigure) (struct usb_gadget *)) +{ + *open = usb_gadget_cfs_open; + *close = usb_gadget_cfs_close; + *enable = usb_gadget_cfs_enable; + *disable = usb_gadget_cfs_disable; + *reconfigure = usb_gadget_cfs_reconfigure_gadget; +} diff --git a/src/usb/usb-gadget-legacy-gadget.c b/src/usb/usb-gadget-legacy-gadget.c new file mode 100644 index 0000000..aa1f6b1 --- /dev/null +++ b/src/usb/usb-gadget-legacy-gadget.c @@ -0,0 +1,358 @@ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "usb-gadget.h" + +#define MAX_GADGET_STR_LEN 256 + +#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" + +/* 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" + +static bool legacy_is_function_supported(struct usb_function *func) +{ + char buf[PATH_MAX]; + + snprintf (buf, sizeof(buf), "%s/f_%s", LEGACY_ROOTPATH, func->name); + if (access(buf, F_OK)) + return false; + + return true; +} + +static bool legacy_is_gadget_supported(struct usb_gadget *gadget) +{ + int i, j; + struct usb_configuration *config; + + if (!gadget || !gadget->configs || !gadget->configs[0] || !gadget->configs[0]->funcs[0]) + return false; + + if (!gadget->attrs.idVendor || !gadget->attrs.idProduct || !gadget->attrs.bcdDevice) + return false; + + /* only strings in US_en are allowed */ + if (gadget->strs.lang_code != DEFAULT_LANG) + return false; + + if (!gadget->strs.manufacturer || !gadget->strs.product) + return false; + + for (j = 0; gadget->configs[j]; ++j) { + config = gadget->configs[j]; + + if (!config->funcs) + return false; + + for (i = 0; config->funcs[i]; ++i) + if (!legacy_is_function_supported(config->funcs[i])) + return false; + } + + return true; +} + +/* TODO. Maybe move this to sys ? */ +static int legacy_set_int_hex(char *path, int val) +{ + int r; + char buf[MAX_GADGET_STR_LEN]; + + 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); + if (ret) + return ret; + + return 0; +} + +static int legacy_set_gadget_strs(struct usb_gadget_strings *strs) +{ + int ret; + + if (!strs->manufacturer || !strs->product) + return -EINVAL; + + ret = sys_set_str(LEGACY_IMANUFACTURER_PATH, strs->manufacturer); + if (ret) + return ret; + + ret = sys_set_str(LEGACY_IPRODUCT_PATH, strs->product); + if (ret) + return ret; + + /* The serial is written by the slp gadget kernel driver */ + + return 0; +} + +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 void legacy_start_stop_service_and_handler(bool start) +{ + int i; + int ret; + int n_func = 0; + char *ptr; + char *begin; + char *fname; + char *sep = LEGACY_FUNC_SEP; + char buf[MAX_GADGET_STR_LEN]; + struct usb_function *func; + struct usb_function *funcs[USB_FUNCTION_IDX_MAX]; + + /* SLP gadget uses two USB configuration. + * (/sys/class/usb_mode/usb0/funcs_fconf and /sys/class/usb_mode/usb0/funcs_sconf) + * + * One usb function can be included in two configurations simultaneously. + * In this situation, a handler associated with function can be called twice for a usb function. + * To prevent duplicate calls, + * Collect all functions and remove duplicates and process them. + */ + + /* First configuration */ + ret = sys_get_str(LEGACY_CONFIG_1_PATH, buf, sizeof(buf)); + if (ret) + goto second_configuration; + + /* Caution: buf ends with '\n' */ + ptr = strchr(buf, '\n'); + if (ptr) + *ptr = 0; + + begin = buf; + for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { + func = find_usb_function_by_name(fname); + if (!func) + continue; + + for (i = 0; i < n_func; i++) + if (funcs[i] == func) + continue; + + if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */ + break; + + funcs[n_func] = func; + n_func++; + } + + /* Second configuration */ +second_configuration: + ret = sys_get_str(LEGACY_CONFIG_2_PATH, buf, sizeof(buf)); + if (ret) + return; + + /* Caution: buf ends with '\n' */ + ptr = strchr(buf, '\n'); + if (ptr) + *ptr = 0; + + begin = buf; + for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { + func = find_usb_function_by_name(fname); + if (!func) + continue; + + for (i = 0; i < n_func; i++) + if (funcs[i] == func) + continue; + + if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */ + break; + + funcs[n_func] = func; + n_func++; + } + + for (i = 0; i < n_func; i++) { + if (start) { + if (funcs[i]->handler) + funcs[i]->handler(1); + + if (funcs[i]->service) + (void)systemd_start_unit_wait_started(funcs[i]->service, ".service", -1); + } else { + if (funcs[i]->service && !funcs[i]->remain_after_disable) + (void)systemd_stop_unit_wait_stopped(funcs[i]->service, ".service", -1); + + if (funcs[i]->handler) + funcs[i]->handler(0); + } + } +} + +static int usb_gadget_legacy_enable(void) +{ + int ret; + + ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE); + if (ret < 0) + return ret; + + legacy_start_stop_service_and_handler(true); + + return 0; +} + +static int usb_gadget_legacy_disable(void) +{ + legacy_start_stop_service_and_handler(false); + + return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE); +} + +static int usb_gadget_legacy_reconfigure_gadget(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget) + return -EINVAL; + + /* Verify the gadget and check if function is supported */ + if (!legacy_is_gadget_supported(gadget)) + return -ENOTSUP; + + ret = legacy_set_gadget_attrs(&gadget->attrs); + if (ret) + return ret; + + ret = legacy_set_gadget_strs(&gadget->strs); + 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]); + if (ret) + return ret; + + return 0; +} + +static int usb_gadget_legacy_open(void) +{ + return 0; +} + +static int usb_gadget_legacy_close(void) +{ + return 0; +} + +int usb_gadget_legacy_supported(void) +{ + int ret; + + ret = (access("/sys/class/usb_mode/usb0/enable", F_OK) == 0); + if (ret) + CRITICAL_LOG("Usb-gadget is supported via legacy samsung gadget."); + + return ret; +} + +void usb_gadget_bind_legacy_gadget(int (**open) (void), int (**close) (void), int (**enable) (void), + int (**disable) (void), int (**reconfigure) (struct usb_gadget *)) +{ + *open = usb_gadget_legacy_open; + *close = usb_gadget_legacy_close; + *enable = usb_gadget_legacy_enable; + *disable = usb_gadget_legacy_disable; + *reconfigure = usb_gadget_legacy_reconfigure_gadget; +} diff --git a/src/usb/usb-gadget.c b/src/usb/usb-gadget.c new file mode 100644 index 0000000..efa1da8 --- /dev/null +++ b/src/usb/usb-gadget.c @@ -0,0 +1,465 @@ +#include +#include + +#include +#include +#include + +#include + +#include "usb-gadget.h" + +static int (*__usb_gadget_open) (void); +static int (*__usb_gadget_close) (void); +static int (*__usb_gadget_enable) (void); +static int (*__usb_gadget_disable) (void); +static int (*__usb_gadget_reconfigure) (struct usb_gadget *gadget); + +/* temporary extern access */ +struct _usb_mode_mapping_table { + int mode_v; /* Integer defined by vconf */ + unsigned int mode; /* Bitmap of usb function combination */ + struct usb_gadget_attrs attrs; +}; +extern GList *usb_mode_mapping_table_custom; + +static void rndis_handler(int enable) +{ + if (enable) + (void)systemd_start_unit_wait_started("rndis.service", NULL, -1); + else + (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1); +} + +#define DEFINE_USB_FUNCTION(_id, _name, _is_functionfs, _service, _handler) \ + static struct usb_function _##_name##_function = { \ + .id = _id, \ + .name = #_name, \ + .instance = "default", \ + .is_functionfs = _is_functionfs, \ + .service = _service, \ + .remain_after_disable = 0, \ + .handler = _handler, \ + } + +DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, 1, "mtp-responder", NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, 0, "data-router", NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, 1, "sdbd", NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, 0, "sshd", rndis_handler); +DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, 1, "diag", NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, 0, NULL, NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, 0, NULL, NULL); +DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, 0, NULL, NULL); + +#undef DEFINE_USB_FUNCTION + +/* Caution: index order of arrary is important, because simple_translator_open() uses it. */ +static struct usb_function *_available_funcs[] = { + [USB_FUNCTION_IDX_MTP] = &_mtp_function, + [USB_FUNCTION_IDX_ACM] = &_acm_function, + [USB_FUNCTION_IDX_SDB] = &_sdb_function, + [USB_FUNCTION_IDX_RNDIS] = &_rndis_function, + [USB_FUNCTION_IDX_DIAG] = &_diag_function, + [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function, + [USB_FUNCTION_IDX_DM] = &_dm_function, + [USB_FUNCTION_IDX_RMNET] = &_rmnet_function, + [USB_FUNCTION_IDX_MAX] = NULL /* An indicator to end the array */ +}; +static struct usb_function *find_usb_function_by_id(int id); + +struct usb_function *find_usb_function_by_name(const char *name) +{ + int i; + + if(!name || !name[0]) + return NULL; + + for (i = 0; _available_funcs[i]; i++) + if (!strcmp(name, _available_funcs[i]->name)) + return _available_funcs[i]; + + return NULL; +} + +struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance) +{ + int i; + + if(!name || !name[0] || !instance || !instance[0]) + return NULL; + + for (i = 0; _available_funcs[i]; ++i) + if (!strcmp(name, _available_funcs[i]->name) && !strcmp(instance, _available_funcs[i]->instance)) + return _available_funcs[i]; + + return NULL; +} + +static void simple_cleanup_config(struct usb_configuration *config) +{ + if (!config) + return; + + free(config->strs.config_str); + + if (config->funcs) + free(config->funcs); + + free(config); +} + +static void cleanup_gadget(struct usb_gadget *gadget) +{ + int i; + + if (!gadget) + return; + + free(gadget->strs.manufacturer); + free(gadget->strs.product); + free(gadget->strs.serial); + + if (gadget->configs) { + for (i = 0; gadget->configs[i]; ++i) + simple_cleanup_config(gadget->configs[i]); + + free(gadget->configs); + } + + free(gadget); +} + +static int alloc_default_config(struct usb_configuration **_config) +{ + struct usb_configuration *config; + + config = calloc(1, sizeof(*config)); + if (!config) + return -ENOMEM; + + config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES; + config->attrs.MaxPower = DEFAULT_MAX_POWER; + + /* TODO. Here is where to set the string used in config of configfs */ + + *_config = config; + + return 0; +} + +static int alloc_default_gadget(char *serial, struct usb_gadget **_gadget) +{ + struct usb_gadget *gadget; + struct usb_configuration **configs; + + gadget = calloc(1, sizeof(*gadget)); + if (!gadget) + goto out; + + gadget->attrs.idVendor = DEFAULT_VID; + gadget->attrs.idProduct = DEFAULT_PID; + gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE; + + gadget->strs.lang_code = DEFAULT_LANG; + gadget->strs.manufacturer = strdup(DEFAULT_MANUFACTURER); + gadget->strs.product = strdup(DEFAULT_PRODUCT); + gadget->strs.serial = strdup(serial); + + if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial) + goto free_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(gadget->strs.manufacturer); + free(gadget->strs.product); + free(gadget->strs.serial); + free(gadget); +out: + return -ENOMEM; +} + +static int id_to_gadget(struct usb_gadget_id *gadget_id, char *serial, struct usb_gadget **_gadget) +{ + int ret; + int i, j; + int n_configs; + struct usb_gadget *gadget; + int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */ + + GList *elem; + const struct _usb_mode_mapping_table *cm = NULL; + + if (!gadget_id || !serial || !_gadget) + return -EINVAL; + + ret = alloc_default_gadget(serial, &gadget); + if (ret) + goto out; + + /* find custom mode */ + SYS_G_LIST_FOREACH(usb_mode_mapping_table_custom, elem, cm) { + if (cm->mode == gadget_id->function_mask) + break; + } + + if (cm) { + int i, j; + + j = 0; + n_configs = 1; + for (i = 0; i < USB_FUNCTION_IDX_MAX; ++i) { + if (cm->mode & (1 << i)) + functions[0][j++] = (1 << i); + } + functions[0][j] = 0; + + if (cm->attrs.idVendor) + gadget->attrs.idVendor = cm->attrs.idVendor; + if (cm->attrs.idProduct) + gadget->attrs.idProduct = cm->attrs.idProduct; + + } else { + /* + * 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) { + /* MTP, ACM, SDB */ + case USB_FUNCTION_MTP | USB_FUNCTION_ACM: + n_configs = 1; + functions[0][0] = USB_FUNCTION_MTP; + functions[0][1] = USB_FUNCTION_ACM; + 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; + + /* DIAG */ + 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; + + /* RNDIS */ + 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_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_RNDIS: + n_configs = 1; + functions[0][0] = USB_FUNCTION_RNDIS; + functions[0][1] = USB_FUNCTION_ACM; + functions[0][2] = USB_FUNCTION_SDB; + functions[0][3] = 0; + gadget->attrs.idProduct = 0x6864; + break; + + /* RMNET */ + case USB_FUNCTION_DIAG | USB_FUNCTION_RMNET: + n_configs = 1; + functions[0][0] = USB_FUNCTION_DIAG; + functions[0][1] = USB_FUNCTION_RMNET; + functions[0][2] = 0; + gadget->attrs.idProduct = 0x685d; + break; + + /* DM */ + 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; + + default: + ret = -EINVAL; + goto free_gadget; + }; + } + + for (j = 0; j < n_configs; ++j) { + int n_funcs_in_config; + struct usb_configuration *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_usb_function_by_id(functions[j][i]); + if (!config->funcs[i]) + goto free_configs; + } + } + + *_gadget = gadget; + + return 0; + +free_configs: +free_gadget: + cleanup_gadget(gadget); +out: + return ret; +} + + +static struct usb_function *find_usb_function_by_id(int id) +{ + int i; + + for (i = 0; _available_funcs[i]; i++) + if (_available_funcs[i]->id == id) + return _available_funcs[i]; + + return NULL; +} + + +int usb_gadget_enable(void) +{ + if (!__usb_gadget_enable) { + _E("Not supported usb_gadget_enable."); + return -ENOTSUP; + } + + return __usb_gadget_enable(); +} + +int usb_gadget_disable(void) +{ + if (!__usb_gadget_disable) { + _E("Not supported usb_gadget_disable."); + return -ENOTSUP; + } + + return __usb_gadget_disable(); +} + +int usb_gadget_change_mode(unsigned int mode) +{ + struct usb_gadget *gadget; + struct usb_gadget_id gadget_id = {0, }; + char serial[] = "123456"; + int ret; + + if (!__usb_gadget_reconfigure) { + _E("Not supported usb_gadget_reconfigure."); + return -ENOTSUP; + } + + gadget_id.function_mask = mode; + + ret = id_to_gadget(&gadget_id, serial, &gadget); + if (ret) { + _E("Failed to id_to_gadget, %d", ret); + return ret; + } + + ret = __usb_gadget_reconfigure(gadget); + cleanup_gadget(gadget); + if (ret) { + _E("Failed to reconfigure gadget, %d", ret); + return ret; + } + + return 0; +} + +int usb_gadget_init(void) +{ + if (usb_gadget_legacy_supported()) { + /* legacy samsung gadget */ + usb_gadget_bind_legacy_gadget(&__usb_gadget_open, + &__usb_gadget_close, + &__usb_gadget_enable, + &__usb_gadget_disable, + &__usb_gadget_reconfigure); + } else if (usb_gadget_cfs_supported()) { + /* configfs/functionfs gadget */ + usb_gadget_bind_cfs_gadget(&__usb_gadget_open, + &__usb_gadget_close, + &__usb_gadget_enable, + &__usb_gadget_disable, + &__usb_gadget_reconfigure); + } else { + CRITICAL_LOG("Usb-gadget is not supported."); + return -ENOTSUP; + } + + /* open supported usb-gadget */ + __usb_gadget_open(); + + /* Use mtp-responder-dummy.socket when there is no mtp-responser.socket. + * + * The mtp-responder.socket is special in the configfs environment. + * If mtp-responder.socket is missing, gadget configuration will fail. + * As a result, all usb operations do not work properly. + * So in environments that mtp doesn't support, use dummy mtp. + */ + if (access("/usr/lib/systemd/system/mtp-responder.socket", F_OK)) { + _available_funcs[USB_FUNCTION_IDX_MTP]->service = "mtp-responder-dummy"; + } + + return 0; +} + +int usb_gadget_exit(void) +{ + if (__usb_gadget_close) + __usb_gadget_close(); + + __usb_gadget_open = NULL; + __usb_gadget_close = NULL; + __usb_gadget_enable = NULL; + __usb_gadget_disable = NULL; + __usb_gadget_reconfigure = NULL; + + return 0; +} diff --git a/src/usb/usb-gadget.h b/src/usb/usb-gadget.h new file mode 100644 index 0000000..161be96 --- /dev/null +++ b/src/usb/usb-gadget.h @@ -0,0 +1,101 @@ +#ifndef __USB_GADGET_H__ +#define __USB_GADGET_H__ + +#include +#include + +/*The default USB configuration */ +#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 + +struct usb_function { + int id; + const char *name; + const char *instance; + + int is_functionfs; + const char *service; + + /* do not stop the service on disabling usb-gadget function */ + int remain_after_disable; + + void (*handler)(int enable); +}; + +struct usb_configuration_attributes { + uint8_t bmAttributs; + int MaxPower; +}; + +struct usb_configuration_strings { + uint16_t lang_code; + char *config_str; +}; + +struct usb_configuration { + struct usb_configuration_attributes attrs; + struct usb_configuration_strings strs; + struct usb_function **funcs; +}; + +struct usb_gadget_attrs { + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; +}; + +struct usb_gadget_strings { + uint16_t lang_code; + char *manufacturer; + char *product; + char *serial; +}; + +struct usb_gadget { + struct usb_gadget_attrs attrs; + struct usb_gadget_strings strs; + struct usb_configuration **configs; +}; + +struct usb_gadget_id { + unsigned int function_mask; +}; + +struct usb_function *find_usb_function_by_name(const char *name); +struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance); + +int usb_gadget_enable(void); +int usb_gadget_disable(void); +int usb_gadget_change_mode(unsigned int mode); +int usb_gadget_init(void); +int usb_gadget_exit(void); + +/* legacy samsung gadget */ +int usb_gadget_legacy_supported(void); +void usb_gadget_bind_legacy_gadget(int (**open) (void), + int (**close) (void), + int (**enable) (void), + int (**disable) (void), + int (**reconfigure) (struct usb_gadget *)); + +/* configfs/functionfs gadget */ +int usb_gadget_cfs_supported(void); +void usb_gadget_bind_cfs_gadget(int (**open) (void), + int (**close) (void), + int (**enable) (void), + int (**disable) (void), + int (**reconfigure) (struct usb_gadget *)); + +#endif //__USB_GADGET_H__ diff --git a/src/usb/usb-state.c b/src/usb/usb-state.c index 51fa4cb..d05f9a3 100644 --- a/src/usb/usb-state.c +++ b/src/usb/usb-state.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "core/log.h" @@ -30,6 +29,7 @@ #include "usb.h" #include "usb-debug.h" +#include "usb-gadget.h" #define PATH_USB_GADGET_CONF "/hal/etc/deviced/usb_gadget.conf" diff --git a/src/usb/usb-tethering.c b/src/usb/usb-tethering.c index e0ed34f..f0d7142 100644 --- a/src/usb/usb-tethering.c +++ b/src/usb/usb-tethering.c @@ -20,7 +20,6 @@ #include #include -#include #include "core/log.h" #include "shared/device-notifier.h" diff --git a/src/usb/usb.c b/src/usb/usb.c index 6792310..c71da85 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -19,8 +19,6 @@ #include #include -#include -#include #include "core/log.h" #include "core/udev.h" @@ -29,6 +27,7 @@ #include "shared/plugin.h" #include "usb.h" +#include "usb-gadget.h" #include "usb-debug.h" #include "usb-tethering.h" @@ -48,7 +47,7 @@ static int usb_change_gadget(unsigned mode) { int ret; - ret = hal_device_usb_gadget_change_mode(mode); + ret = usb_gadget_change_mode(mode); if (ret) { /* because usb does not work properly */ (void)usb_state_set_current_mode(USB_FUNCTION_NONE); @@ -65,7 +64,7 @@ static int usb_enable(unsigned int mode) { int ret; - ret = hal_device_usb_gadget_enable(); + ret = usb_gadget_enable(); if (ret < 0) { _E("Failed to enable USB config: %d", ret); goto out; @@ -91,7 +90,7 @@ static int usb_disable(void) (void)usb_state_set_current_mode(USB_FUNCTION_NONE); change_usb_state_notification_handler(USB_FUNCTION_NONE); - ret = hal_device_usb_gadget_disable(); + ret = usb_gadget_disable(); if (ret < 0) { _E("Failed to disable USB config: %d", ret); return ret; @@ -286,7 +285,7 @@ static void usb_init(void *data) usb_state_load_custom_mode(); usb_state_retrieve_selected_mode(); - ret = hal_device_usb_gadget_get_backend(); + ret = usb_gadget_init(); if (ret < 0) { _E("USB client cannot be used: %d", ret); return; @@ -319,8 +318,9 @@ static void usb_exit(void *data) change_usb_state_notification_handler(USB_FUNCTION_NONE); unregister_udev_uevent_control(&uh); - (void)hal_device_usb_gadget_disable(); - hal_device_usb_gadget_put_backend(); + usb_gadget_disable(); + usb_gadget_exit(); + } static struct extcon_ops extcon_usb_ops = { -- 2.7.4