summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--hw/usb_cfs_client_common.c128
-rw-r--r--hw/usb_client_common.c67
-rw-r--r--hw/usb_gadget.h246
-rw-r--r--hw/usb_gadget_common.c198
-rw-r--r--mtp-responder-dummy/descsbin0 -> 80 bytes
-rw-r--r--mtp-responder-dummy/mtp-responder-dummy.service12
-rw-r--r--mtp-responder-dummy/mtp-responder-dummy.socket6
-rw-r--r--mtp-responder-dummy/strsbin0 -> 30 bytes
-rw-r--r--packaging/libdevice-node.spec4
-rw-r--r--unittest/device_haltests.cpp8
11 files changed, 332 insertions, 343 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 452fae7..4646bb0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,12 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hw/ DESTINATION include/hw
CONFIGURE_FILE(hwcommon.pc.in hwcommon.pc @ONLY)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hwcommon.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+# dummy mtp responder
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mtp-responder-dummy/strs DESTINATION /etc/mtp-responder-dummy)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mtp-responder-dummy/descs DESTINATION /etc/mtp-responder-dummy)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mtp-responder-dummy/mtp-responder-dummy.socket DESTINATION /usr/lib/systemd/system)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mtp-responder-dummy/mtp-responder-dummy.service DESTINATION /usr/lib/systemd/system)
+
IF(BUILD_GTESTS STREQUAL on)
ADD_SUBDIRECTORY(unittest)
ENDIF()
diff --git a/hw/usb_cfs_client_common.c b/hw/usb_cfs_client_common.c
index b3ddee2..d594fd2 100644
--- a/hw/usb_cfs_client_common.c
+++ b/hw/usb_cfs_client_common.c
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/mount.h>
#include <usbg/usbg.h>
+#include <usbg/function/net.h>
#include <unistd.h>
#include <libsyscommon/dbus-systemd.h>
@@ -205,7 +206,7 @@ static int cfs_find_func(const char *name, const char *instance)
{
int i;
- for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
+ for (i = 0; _available_funcs[i]; ++i)
if (cfs_match_func(_available_funcs[i], name, instance))
return i;
@@ -496,18 +497,12 @@ static bool cfs_is_function_supported(struct usb_client *usb,
bool res;
int ret;
- switch (func->function_group) {
- case USB_FUNCTION_GROUP_SIMPLE:
- case USB_FUNCTION_GROUP_WITH_POST_SERVICE:
+ if (!func->ffs_service) {
ret = usbg_lookup_function_type(func->name);
res = ret >= 0;
- break;
- case USB_FUNCTION_GROUP_WITH_SERVICE:
+ } else {
/* TODO: Check if socket is available */
res = true;
- break;
- default:
- res = false;
}
return res;
@@ -612,6 +607,8 @@ static int cfs_prep_ffs_service(const char *name, const char *instance,
int ret;
/* TODO: Add some good error handling */
+ if (!socket_name)
+ return -EINVAL;
left = sizeof(buf);
pos = buf;
@@ -662,6 +659,37 @@ umount_ffs:
return ret;
}
+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, &ethaddr);
+
+ return ret;
+}
+
static int cfs_set_gadget_config(struct cfs_client *cfs_client,
int config_id,
struct usb_configuration *usb_config)
@@ -702,28 +730,21 @@ static int cfs_set_gadget_config(struct cfs_client *cfs_client,
int type;
usbg_function *func;
- switch (usb_func->function_group) {
- case USB_FUNCTION_GROUP_SIMPLE:
- case USB_FUNCTION_GROUP_WITH_POST_SERVICE:
+ if (!usb_func->ffs_service) {
type = usbg_lookup_function_type(usb_func->name);
if (strlen(usb_func->instance) >= MAX_INSTANCE_LEN)
return -ENAMETOOLONG;
strncpy(instance, usb_func->instance, MAX_INSTANCE_LEN);
instance[MAX_INSTANCE_LEN - 1] = '\0';
- break;
- case USB_FUNCTION_GROUP_WITH_SERVICE:
+ } else {
type = USBG_F_FFS;
ret = snprintf(instance, sizeof(instance), "%s%c%s",
usb_func->name, NAME_INSTANCE_SEP,
usb_func->instance);
if (ret < 0 || ret >= sizeof(instance))
return -ENAMETOOLONG;
- break;
- default:
- return -EINVAL;
}
-
func = usbg_get_function(cfs_client->gadget, type, instance);
if (!func) {
ret = usbg_create_function(cfs_client->gadget,
@@ -733,21 +754,20 @@ static int cfs_set_gadget_config(struct cfs_client *cfs_client,
if (ret)
return ret;
- if (usb_func->function_group ==
- USB_FUNCTION_GROUP_WITH_SERVICE) {
- struct usb_function_with_service *fws;
+ /* 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(func) == USBG_F_RNDIS)
+ (void)cfs_set_rndis_mac_addr(cfs_client->gadget, func); /* A random value is used if fails */
- fws = container_of(usb_func,
- struct usb_function_with_service,
- func);
+ if (usb_func->ffs_service) {
ret = cfs_prep_ffs_service(usb_func->name,
- usb_func->instance,
- instance,
- fws->service);
+ usb_func->instance,
+ instance,
+ usb_func->ffs_service);
if (ret)
return ret;
}
-
}
ret = usbg_add_config_function(config, NULL, func);
@@ -806,22 +826,6 @@ static int cfs_reconfigure_gadget(struct usb_client *usb,
goto out;
}
- /* Workaround for enabling extcon notification */
- /* ******************************************* */
- /* ******************************************* */
- {
- const char *ARTIK_UDC_NAME = "c0040000.dwc2otg";
- const char *udc_name = usbg_get_udc_name(cfs_client->udc);
- if (udc_name && !strncmp(udc_name, ARTIK_UDC_NAME, strlen(ARTIK_UDC_NAME))) {
- ret = usbg_enable_gadget(cfs_client->gadget, cfs_client->udc);
- if (ret)
- goto out;
- }
- }
- /* ******************************************* */
- /* ******************************************* */
- /* ******************************************* */
-
ret = cfs_cleanup_left_configs(cfs_client, i);
/* TODO
@@ -836,8 +840,8 @@ static int cfs_enable(struct usb_client *usb)
int i;
int ret;
struct usb_gadget *gadget;
+ struct usb_function *func;
struct cfs_client *cfs_client;
- struct usb_function_with_service *fws;
if (!usb)
return -EINVAL;
@@ -854,11 +858,13 @@ static int cfs_enable(struct usb_client *usb)
}
for (i = 0; gadget->funcs[i]; ++i) {
- if (gadget->funcs[i]->function_group != USB_FUNCTION_GROUP_WITH_POST_SERVICE)
- continue;
+ func = gadget->funcs[i];
+
+ if (func->handler)
+ func->handler(1);
- fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
- (void)systemd_start_unit_wait_started(fws->service, ".service", -1);
+ if (func->service)
+ (void)systemd_start_unit_wait_started(func->service, ".service", -1);
}
cfs_free_gadget(gadget);
@@ -871,8 +877,8 @@ static int cfs_disable(struct usb_client *usb)
int i;
int ret;
struct usb_gadget *gadget;
+ struct usb_function *func;
struct cfs_client *cfs_client;
- struct usb_function_with_service *fws;
if (!usb)
return -EINVAL;
@@ -882,11 +888,13 @@ static int cfs_disable(struct usb_client *usb)
return ret;
for (i = 0; gadget->funcs[i]; ++i) {
- if (gadget->funcs[i]->function_group != USB_FUNCTION_GROUP_WITH_POST_SERVICE)
- continue;
+ func = gadget->funcs[i];
+
+ if (func->service)
+ (void)systemd_stop_unit_wait_stopped(func->service, ".service", -1);
- fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
- (void)systemd_stop_unit_wait_stopped(fws->service, ".service", -1);
+ if (func->handler)
+ func->handler(0);
}
cfs_free_gadget(gadget);
@@ -970,15 +978,9 @@ int hw_cfs_gadget_close(struct hw_common *common)
continue;
usb_func = _available_funcs[ret];
- if (usb_func->function_group ==
- USB_FUNCTION_GROUP_WITH_SERVICE) {
- struct usb_function_with_service *fws;
-
- fws = container_of(usb_func,
- struct usb_function_with_service,
- func);
- systemd_stop_unit_wait_stopped(fws->service, ".socket", -1);
- systemd_stop_unit_wait_stopped(fws->service, ".service", -1);
+ if (usb_func->ffs_service) {
+ systemd_stop_unit_wait_stopped(usb_func->ffs_service, ".socket", -1);
+ systemd_stop_unit_wait_stopped(usb_func->ffs_service, ".service", -1);
}
}
diff --git a/hw/usb_client_common.c b/hw/usb_client_common.c
index dc08bde..d008485 100644
--- a/hw/usb_client_common.c
+++ b/hw/usb_client_common.c
@@ -95,13 +95,13 @@ 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, base) \
- do { \
+#define GET_VALUE_FROM_SYSFS(path, field, type, base) \
+ do { \
ret = get_int_from_file(path, &val, base); \
- if (ret) \
- return ret; \
- \
- gadget->attrs.field = (type)val; \
+ if (ret) \
+ return ret; \
+ \
+ gadget->attrs.field = (type)val; \
} while (0)
GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t, 0);
@@ -146,7 +146,7 @@ static int legacy_find_func(const char *name)
{
int i;
- for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
+ for (i = 0; _available_funcs[i]; ++i)
if (!strcmp(name, _available_funcs[i]->name))
return i;
@@ -463,15 +463,13 @@ static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
*/
if (strs->manufacturer) {
- ret = sys_set_str(LEGACY_IMANUFACTURER_PATH,
- 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);
+ ret = sys_set_str(LEGACY_IPRODUCT_PATH, strs->product);
if (ret)
return ret;
}
@@ -540,13 +538,12 @@ static int legacy_reconfigure_gadget(struct usb_client *usb,
static int legacy_enable(struct usb_client *usb)
{
- int ret;
int i;
+ int ret;
struct usb_gadget *gadget;
- struct usb_function_with_service *fws;
+ struct usb_function *func;
- ret = sys_set_str(LEGACY_ENABLE_PATH,
- LEGACY_ENABLE);
+ ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE);
if (ret < 0)
return ret;
@@ -555,11 +552,21 @@ static int legacy_enable(struct usb_client *usb)
goto disable_gadget;
for (i = 0; gadget->funcs[i]; ++i) {
- if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
- continue;
+ func = gadget->funcs[i];
+
+ if (func->handler)
+ func->handler(1);
- fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
- (void)systemd_start_unit_wait_started(fws->service, ".service", -1);
+ /*
+ * Reuse configfs data structure to simplify design.
+ * Configfs has a special service for functionfs. (E.g. sdbd and mtp-responder)
+ * The legacy usb gadget must handle both services.
+ */
+ if (func->ffs_service)
+ (void)systemd_start_unit_wait_started(func->ffs_service, ".service", -1);
+
+ if (func->service)
+ (void)systemd_start_unit_wait_started(func->service, ".service", -1);
}
legacy_free_gadget(gadget);
@@ -572,21 +579,31 @@ disable_gadget:
static int legacy_disable(struct usb_client *usb)
{
- int ret;
int i;
+ int ret;
struct usb_gadget *gadget;
- struct usb_function_with_service *fws;
+ struct usb_function *func;
ret = legacy_get_current_gadget(usb, &gadget);
if (ret < 0)
return ret;
for (i = 0; gadget->funcs[i]; ++i) {
- if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
- continue;
+ func = gadget->funcs[i];
+
+ /*
+ * Reuse configfs data structure to simplify design.
+ * Configfs has a special service for functionfs. (E.g. sdbd and mtp-responder)
+ * The legacy usb gadget must handle both services.
+ */
+ if (func->service)
+ (void)systemd_stop_unit_wait_stopped(func->service, ".service", -1);
+
+ if (func->ffs_service)
+ (void)systemd_stop_unit_wait_stopped(func->ffs_service, ".service", -1);
- fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
- (void)systemd_stop_unit_wait_stopped(fws->service, ".service", -1);
+ if (func->handler)
+ func->handler(0);
}
ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
diff --git a/hw/usb_gadget.h b/hw/usb_gadget.h
index e3f460b..fe909ed 100644
--- a/hw/usb_gadget.h
+++ b/hw/usb_gadget.h
@@ -36,45 +36,54 @@
*/
#define USB_GADGET_DEVICE_VERSION MAKE_VERSION(0,1)
-#define _HELPER_Y(x) ((x) & -(x))
+typedef enum {
+ USB_FUNCTION_IDX_MTP = 0,
+ USB_FUNCTION_IDX_ACM = 1,
+ USB_FUNCTION_IDX_SDB = 2,
+ USB_FUNCTION_IDX_RNDIS = 3,
+ USB_FUNCTION_IDX_DIAG = 4,
+ USB_FUNCTION_IDX_CONN_GADGET = 5,
+ USB_FUNCTION_IDX_DM = 6,
+ USB_FUNCTION_IDX_RMNET = 7,
+ USB_FUNCTION_IDX_MAX = USB_FUNCTION_IDX_RMNET + 1
+} usb_function_idx_e;
-/* Count number of trailing zeros using Dean Gaudet's algorithm */
-#define _HELPER_CTZ(mask) \
- ((_HELPER_Y(mask) ? 0 : 1) + \
- ((_HELPER_Y(mask) & 0x0000FFFF) ? 0 : 16) + \
- ((_HELPER_Y(mask) & 0x00FF00FF) ? 0 : 8) + \
- ((_HELPER_Y(mask) & 0x0F0F0F0F) ? 0 : 4) + \
- ((_HELPER_Y(mask) & 0x33333333) ? 0 : 2) + \
- ((_HELPER_Y(mask) & 0x55555555) ? 0 : 1))
+typedef enum {
+ USB_FUNCTION_NONE = 0,
+ USB_FUNCTION_MTP = 1 << USB_FUNCTION_IDX_MTP,
+ USB_FUNCTION_ACM = 1 << USB_FUNCTION_IDX_ACM,
+ USB_FUNCTION_SDB = 1 << USB_FUNCTION_IDX_SDB,
+ USB_FUNCTION_RNDIS = 1 << USB_FUNCTION_IDX_RNDIS,
+ USB_FUNCTION_DIAG = 1 << USB_FUNCTION_IDX_DIAG,
+ USB_FUNCTION_CONN_GADGET = 1 << USB_FUNCTION_IDX_CONN_GADGET,
+ USB_FUNCTION_DM = 1 << USB_FUNCTION_IDX_DM,
+ USB_FUNCTION_RMNET = 1 << USB_FUNCTION_IDX_RMNET
+} usb_function_e;
-/* Function IDX in array is number of trailing zeros */
-#define FUNC_IDX_FROM_MASK(mask) _HELPER_CTZ(mask)
-/**
- * USB_FUNCTION_GROUP_WITH_POST_SERVICE is the same as USB_FUNCTION_GROUP_SIMPLE
- * except running the service as a post.
+/*
+ * legacy enable(usb plug) : enable gadget -> handler(1) -> ffs_service start -> service start
+ * legacy disable(usb unplug) : service stop -> ffs_service stop -> handler(0) -> disable gadget
+ *
+ * configfs init(booting) : ffs_service start
+ * configfs enable(usb plug) : enable gadget -> handler(1) -> service start
+ * configfs disable(usb unplug) : service stop -> handler(0) -> disable gadget
+ * configfs deinit : ffs_service stop
*/
-typedef enum {
- USB_FUNCTION_GROUP_SIMPLE,
- USB_FUNCTION_GROUP_WITH_SERVICE,
- USB_FUNCTION_GROUP_WITH_POST_SERVICE,
-} usb_function_group_e;
-
struct usb_function {
- int function_group;
int id;
const char *name;
const char *instance;
+ const char *ffs_service; /* only used in configfs */
+ const char *service;
+
+ void (*handler)(int enable);
+
int (*clone)(struct usb_function *func, struct usb_function **_clone);
void (*free_func)(struct usb_function *func);
};
-struct usb_function_with_service {
- struct usb_function func;
- const char *service;
-};
-
struct usb_configuration_attributes {
uint8_t bmAttributs;
int MaxPower;
@@ -114,189 +123,6 @@ struct usb_gadget {
struct usb_configuration **configs;
};
-typedef enum {
- USB_FUNCTION_NONE = 0,
- USB_FUNCTION_MTP = 1 << 0,
- USB_FUNCTION_ACM = 1 << 1,
- USB_FUNCTION_SDB = 1 << 2,
- USB_FUNCTION_RNDIS = 1 << 3,
- USB_FUNCTION_DIAG = 1 << 4,
- USB_FUNCTION_CONN_GADGET = 1 << 5,
- USB_FUNCTION_DM = 1 << 6,
- USB_FUNCTION_RMNET = 1 << 7,
-} usb_function_e;
-
-static void free_simple_func_content(struct usb_function *func)
-{
- free((void *)func->name);
- free((void *)func->instance);
-}
-
-static void free_simple_func(struct usb_function *func)
-{
- free_simple_func_content(func);
- free(func);
-}
-
-static int clone_simple_func_to(struct usb_function *func,
- struct usb_function *other)
-{
- *other = *func;
- other->name = strdup(func->name);
- other->instance = strdup(func->instance);
-
- if (!other->name || !other->instance)
- goto free_strs;
-
- return 0;
-free_strs:
- free((void *)other->name);
- free((void *)other->instance);
- return -ENOMEM;
-}
-
-static int clone_simple_func(struct usb_function *func,
- struct usb_function **clone)
-{
- struct usb_function *other;
- int ret;
-
- if (!func || !clone)
- return -EINVAL;
-
- other = (struct usb_function *)malloc(sizeof(*other));
- if (!other)
- goto out;
-
- ret = clone_simple_func_to(func, other);
- if (ret)
- goto free_other;
-
- *clone = other;
- return 0;
-free_other:
- free(other);
-out:
- return -ENOMEM;
-}
-
-#define DEFINE_SIMPLE_USB_FUNCTION(_id, _name) \
- static struct usb_function _##_name##_function = { \
- .function_group = USB_FUNCTION_GROUP_SIMPLE, \
- .id = _id, \
- .name = #_name, \
- .instance = "default", \
- .clone = clone_simple_func, \
- .free_func = free_simple_func, \
- }
-
-DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_DIAG, diag);
-DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet);
-DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_DM, dm);
-DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget);
-
-#undef DEFINE_SIMPLE_USB_FUNCTION
-
-static void free_func_with_service(struct usb_function *func)
-{
- struct usb_function_with_service *fws;
-
- fws = container_of(func, struct usb_function_with_service, func);
-
- free_simple_func_content(func);
- free((void *)fws->service);
- free(fws);
-}
-
-static int clone_func_with_service(struct usb_function *func,
- struct usb_function **clone)
-{
- struct usb_function_with_service *fws;
- struct usb_function_with_service *other;
- int ret;
-
- if (!func || !clone)
- return -EINVAL;
-
- other = (struct usb_function_with_service *)malloc(sizeof(*other));
- if (!other)
- goto out;
-
- ret = clone_simple_func_to(func, &other->func);
- if (ret)
- goto free_other;
-
- fws = container_of(func, struct usb_function_with_service, func);
- if (fws->service) {
- other->service = strdup(fws->service);
- if (!other->service)
- goto free_content;
- } else {
- other->service = NULL;
- }
-
- *clone = &other->func;
- return 0;
-free_content:
- free_simple_func_content(&other->func);
-free_other:
- free(other);
-out:
- return -ENOMEM;
-}
-
-#define DEFINE_USB_FUNCTION_WITH_SERVICE(_id, _name, _service) \
- static struct usb_function_with_service _##_name##_function = { \
- .func = { \
- .function_group = USB_FUNCTION_GROUP_WITH_SERVICE, \
- .id = _id, \
- .name = #_name, \
- .instance = "default", \
- .clone = clone_func_with_service, \
- .free_func = free_func_with_service, \
- }, \
- .service = _service, \
- }
-
-DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_SDB, sdb, "sdbd");
-DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_MTP, mtp, "mtp-responder");
-
-#define DEFINE_USB_FUNCTION_WITH_POST_SERVICE(_id, _name, _service) \
- static struct usb_function_with_service _##_name##_function = { \
- .func = { \
- .function_group = USB_FUNCTION_GROUP_WITH_POST_SERVICE, \
- .id = _id, \
- .name = #_name, \
- .instance = "default", \
- .clone = clone_func_with_service, \
- .free_func = free_func_with_service, \
- }, \
- .service = _service, \
- }
-
-DEFINE_USB_FUNCTION_WITH_POST_SERVICE(USB_FUNCTION_ACM, acm, "data-router");
-DEFINE_USB_FUNCTION_WITH_POST_SERVICE(USB_FUNCTION_RNDIS, rndis, "rndis");
-
-
-#define MAKE_FUNC_AVAILABLE(_name, _vname) \
- [FUNC_IDX_FROM_MASK(USB_FUNCTION_##_name)] = &_##_vname##_function
-
-#define MAKE_FUNC_WS_AVAILABLE(_name, _vname) \
- [FUNC_IDX_FROM_MASK(USB_FUNCTION_##_name)] = &_##_vname##_function.func
-
-static struct usb_function *_available_funcs[] = {
- MAKE_FUNC_WS_AVAILABLE(MTP, mtp),
- MAKE_FUNC_WS_AVAILABLE(ACM, acm),
- MAKE_FUNC_WS_AVAILABLE(SDB, sdb),
- MAKE_FUNC_WS_AVAILABLE(RNDIS, rndis),
- MAKE_FUNC_AVAILABLE(DIAG, diag),
- MAKE_FUNC_AVAILABLE(CONN_GADGET, conn_gadget),
- MAKE_FUNC_AVAILABLE(DM, dm),
- MAKE_FUNC_AVAILABLE(RMNET, rmnet),
-};
-
-#undef MAKE_FUNC_AVAILABLE
-
struct usb_gadget_id {
unsigned int function_mask;
};
@@ -314,4 +140,6 @@ int simple_translator_open(struct hw_info *info,
const char *id, struct hw_common **common);
int simple_translator_close(struct hw_common *common);
+extern struct usb_function *_available_funcs[];
+
#endif
diff --git a/hw/usb_gadget_common.c b/hw/usb_gadget_common.c
index e629b47..fb6a986 100644
--- a/hw/usb_gadget_common.c
+++ b/hw/usb_gadget_common.c
@@ -23,8 +23,10 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
+#include <unistd.h>
+
+#include <libsyscommon/dbus-systemd.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 */
@@ -233,25 +235,34 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
* so in this switch we sort our functions in a correct order
*/
switch (gadget_id->function_mask) {
- case USB_FUNCTION_SDB:
+ case USB_FUNCTION_MTP:
n_configs = 1;
- functions[0][0] = USB_FUNCTION_SDB;
+ functions[0][0] = USB_FUNCTION_MTP;
functions[0][1] = 0;
- gadget->attrs.idProduct = 0x685d;
+ gadget->attrs.idProduct = 0x6860;
break;
- case USB_FUNCTION_MTP:
+ case USB_FUNCTION_ACM:
n_configs = 1;
- functions[0][0] = USB_FUNCTION_MTP;
+ functions[0][0] = USB_FUNCTION_ACM;
functions[0][1] = 0;
gadget->attrs.idProduct = 0x6860;
break;
- case USB_FUNCTION_RNDIS:
+ case USB_FUNCTION_SDB:
n_configs = 1;
- functions[0][0] = USB_FUNCTION_RNDIS;
+ functions[0][0] = USB_FUNCTION_SDB;
functions[0][1] = 0;
- gadget->attrs.idProduct = 0x6863;
+ gadget->attrs.idProduct = 0x685d;
+ break;
+
+ /* 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_ACM | USB_FUNCTION_SDB:
@@ -262,6 +273,14 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
gadget->attrs.idProduct = 0x6860;
break;
+ case USB_FUNCTION_MTP | USB_FUNCTION_SDB:
+ n_configs = 1;
+ functions[0][0] = USB_FUNCTION_MTP;
+ 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;
@@ -271,15 +290,7 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
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
+ /* DIAG */
case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
n_configs = 1;
functions[0][0] = USB_FUNCTION_MTP;
@@ -290,13 +301,19 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
gadget->attrs.idProduct = 0x6860;
break;
- case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM | USB_FUNCTION_DIAG:
+ /* RNDIS */
+ case USB_FUNCTION_RNDIS:
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;
+ functions[0][1] = 0;
+ gadget->attrs.idProduct = 0x6863;
+ break;
+
+ case USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
+ n_configs = 1;
+ functions[0][0] = USB_FUNCTION_SDB;
+ functions[0][1] = USB_FUNCTION_RNDIS;
+ functions[0][2] = 0;
gadget->attrs.idProduct = 0x6864;
break;
@@ -307,40 +324,39 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
functions[0][2] = 0;
gadget->attrs.idProduct = 0x6864;
break;
-#endif
- case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
+ case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
n_configs = 1;
functions[0][0] = USB_FUNCTION_ACM;
functions[0][1] = USB_FUNCTION_SDB;
- functions[0][2] = USB_FUNCTION_DM;
+ functions[0][2] = USB_FUNCTION_RNDIS;
functions[0][3] = 0;
- gadget->attrs.idProduct = 0x6860;
+ gadget->attrs.idProduct = 0x6864;
break;
- case USB_FUNCTION_DIAG | USB_FUNCTION_ACM | USB_FUNCTION_RMNET:
+ /* RMNET */
+ case USB_FUNCTION_DIAG | 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;
+ functions[0][1] = USB_FUNCTION_RMNET;
+ functions[0][2] = 0;
gadget->attrs.idProduct = 0x685d;
break;
- case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM:
+ /* DM */
+ case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
n_configs = 1;
- functions[0][0] = USB_FUNCTION_RNDIS;
+ functions[0][0] = USB_FUNCTION_ACM;
functions[0][1] = USB_FUNCTION_SDB;
- functions[0][2] = USB_FUNCTION_ACM;
+ functions[0][2] = USB_FUNCTION_DM;
functions[0][3] = 0;
- gadget->attrs.idProduct = 0x6864;
+ gadget->attrs.idProduct = 0x6860;
break;
- };
- if (n_configs > 2 || n_configs <= 0) {
+ default:
ret = -EINVAL;
goto free_gadget;
- }
+ };
n_functions = __builtin_popcount(gadget_id->function_mask);
@@ -353,7 +369,7 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
gadget->funcs = funcs;
idx = 0;
- for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i) {
+ for (i = 0; _available_funcs[i]; ++i) {
int func_id = 1 << i;
if (!(gadget_id->function_mask & func_id))
@@ -397,6 +413,99 @@ out:
return ret;
}
+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);
+}
+
+static void free_simple_func(struct usb_function *func)
+{
+ if (func) {
+ free((void *)func->name);
+ free((void *)func->instance);
+ free((void *)func->ffs_service);
+ free((void *)func->service);
+ free(func);
+ }
+}
+
+static int clone_simple_func(struct usb_function *func,
+ struct usb_function **clone)
+{
+ struct usb_function *other;
+
+ if (!func || !clone)
+ return -EINVAL;
+
+ other = (struct usb_function *)calloc(1, sizeof(struct usb_function));
+ if (!other)
+ return -ENOMEM;
+
+ *other = *func;
+
+ other->name = strdup(func->name);
+ other->instance = strdup(func->instance);
+ if (!other->name || !other->instance)
+ goto out_nomem;
+
+ if (func->ffs_service) {
+ other->ffs_service = strdup(func->ffs_service);
+ if (!other->ffs_service)
+ goto out_nomem;
+ }
+
+ if (func->service) {
+ other->service = strdup(func->service);
+ if (!other->service)
+ goto out_nomem;
+ }
+
+ *clone = other;
+ return 0;
+
+out_nomem:
+ free_simple_func(other);
+ return -ENOMEM;
+}
+
+#define DEFINE_USB_FUNCTION(_id, _name, _ffs_service, _service, _handler) \
+ static struct usb_function _##_name##_function = { \
+ .id = _id, \
+ .name = #_name, \
+ .instance = "default", \
+ .ffs_service = _ffs_service, \
+ .service = _service, \
+ .handler = _handler, \
+ .clone = clone_simple_func, \
+ .free_func = free_simple_func, \
+ }
+
+DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, NULL, NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, NULL, NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, NULL, NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, NULL, NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, "sdbd", NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, "mtp-responder", NULL, NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, NULL, "data-router", NULL);
+DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, NULL, "sshd", rndis_handler);
+#undef DEFINE_USB_FUNCTION
+
+/* Caution: index order of arrary is important, because simple_id_to_gadget() uses it. */
+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 */
+};
+
EXPORT
int simple_translator_open(struct hw_info *info,
const char *id, struct hw_common **common)
@@ -414,6 +523,17 @@ int simple_translator_open(struct hw_info *info,
simple_translator->id_to_gadget = simple_id_to_gadget;
simple_translator->cleanup_gadget = simple_cleanup_gadget;
+ /* 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]->ffs_service = "mtp-responder-dummy";
+ }
+
*common = &simple_translator->common;
return 0;
}
diff --git a/mtp-responder-dummy/descs b/mtp-responder-dummy/descs
new file mode 100644
index 0000000..0bffd51
--- /dev/null
+++ b/mtp-responder-dummy/descs
Binary files differ
diff --git a/mtp-responder-dummy/mtp-responder-dummy.service b/mtp-responder-dummy/mtp-responder-dummy.service
new file mode 100644
index 0000000..04e7258
--- /dev/null
+++ b/mtp-responder-dummy/mtp-responder-dummy.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=MTP dummy responder
+StartLimitIntervalSec=0
+
+[Service]
+User=network_fw
+Group=network_fw
+RemainAfterExit=yes
+ExecStart=/usr/bin/true
+SmackProcessLabel=System
+USBFunctionDescriptors=/etc/mtp-responder-dummy/descs
+USBFunctionStrings=/etc/mtp-responder-dummy/strs
diff --git a/mtp-responder-dummy/mtp-responder-dummy.socket b/mtp-responder-dummy/mtp-responder-dummy.socket
new file mode 100644
index 0000000..3f84ab7
--- /dev/null
+++ b/mtp-responder-dummy/mtp-responder-dummy.socket
@@ -0,0 +1,6 @@
+[Unit]
+Description=MTP dummy responder functionfs socket
+
+[Socket]
+ListenUSBFunction=/dev/usb-funcs/mtp/default
+TriggerLimitIntervalSec=0
diff --git a/mtp-responder-dummy/strs b/mtp-responder-dummy/strs
new file mode 100644
index 0000000..b0bd4ab
--- /dev/null
+++ b/mtp-responder-dummy/strs
Binary files differ
diff --git a/packaging/libdevice-node.spec b/packaging/libdevice-node.spec
index 2f9b9f0..809904f 100644
--- a/packaging/libdevice-node.spec
+++ b/packaging/libdevice-node.spec
@@ -54,6 +54,10 @@ make %{?jobs:-j%jobs}
%manifest %{name}.manifest
%license LICENSE.Apache-2.0
%{_libdir}/*.so.*
+%{_unitdir}/mtp-responder-dummy.socket
+%{_unitdir}/mtp-responder-dummy.service
+/etc/mtp-responder-dummy/strs
+/etc/mtp-responder-dummy/descs
%files devel
%manifest %{name}.manifest
diff --git a/unittest/device_haltests.cpp b/unittest/device_haltests.cpp
index ee84de6..4aa0de8 100644
--- a/unittest/device_haltests.cpp
+++ b/unittest/device_haltests.cpp
@@ -1096,14 +1096,10 @@ TEST_F(USBCLIENTHalTest, InitP)
TEST_F(USBCLIENTHalTest, EnableP)
{
int ret;
- char str[256];
if (!supported)
return;
- //dummy code to prevent error for not used function
- snprintf(str, 255, "%s,", _available_funcs[2]->name);
-
if (!client_dev || !client_dev->enable) {
cout << "There is no function for enable" << endl;
return;
@@ -1258,14 +1254,12 @@ TEST_F(USBGADGETHalTest, IdToGadget)
{
struct usb_gadget_id gadget_id;
int ret;
- char str[256];
if (!gadget_translator || !gadget_translator->id_to_gadget) {
cout << "There is no function for id_to_gadget" << endl;
return;
}
- //dummy code to prevent error for not used function
- snprintf(str, 255, "%s,", _available_funcs[2]->name);
+
gadget_id.function_mask = 7;
ret = gadget_translator->id_to_gadget(&gadget_id, &gadget_dev);
EXPECT_EQ(ret, 0) << "Fail to id_to_gadget (" << ret << ")";