summaryrefslogtreecommitdiff
path: root/hw/usb_gadget_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb_gadget_common.c')
-rw-r--r--hw/usb_gadget_common.c346
1 files changed, 160 insertions, 186 deletions
diff --git a/hw/usb_gadget_common.c b/hw/usb_gadget_common.c
index e629b47..d0de9fd 100644
--- a/hw/usb_gadget_common.c
+++ b/hw/usb_gadget_common.c
@@ -16,73 +16,45 @@
* 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>
+#include <stdlib.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"
+#include <libsyscommon/dbus-systemd.h>
-#define DEFAULT_BMATTRIBUTES ((1 << 7) | (1 << 6))
-#define DEFAULT_MAX_POWER 500
+#include <hw/board.h>
+#include <hw/usb_gadget.h>
#ifndef EXPORT
#define EXPORT __attribute__ ((visibility("default")))
#endif
+static struct usb_function *_available_funcs[];
+
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.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)
+static void 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);
- }
+ free(gadget->strs.manufacturer);
+ free(gadget->strs.product);
+ free(gadget->strs.serial);
if (gadget->configs) {
for (i = 0; gadget->configs[i]; ++i)
@@ -91,13 +63,6 @@ static void simple_cleanup_gadget(struct usb_gadget *gadget)
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);
}
@@ -105,25 +70,18 @@ static int alloc_default_config(struct usb_configuration **_config)
{
struct usb_configuration *config;
- config = zalloc(sizeof(*config));
+ config = calloc(1, sizeof(*config));
if (!config)
- goto out;
-
- config->strs = calloc(1, sizeof(*config->strs));
- if (!config->strs)
- goto free_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;
-
-free_config:
- free(config);
-out:
- return -ENOMEM;
}
static int get_device_serial(char **out)
@@ -147,11 +105,9 @@ static int get_device_serial(char **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));
+ gadget = calloc(1, sizeof(*gadget));
if (!gadget)
goto out;
@@ -159,22 +115,15 @@ static int alloc_default_gadget(struct usb_gadget **_gadget)
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);
+ gadget->strs.lang_code = DEFAULT_LANG;
+ gadget->strs.manufacturer = strdup(DEFAULT_MANUFACTURER);
+ gadget->strs.product = strdup(DEFAULT_PRODUCT);
+ if (get_device_serial(&gadget->strs.serial) < 0)
+ gadget->strs.serial = strdup(DEFAULT_SERIAL);
- if (!strs[0].manufacturer || !strs[0].product || !strs[0].serial)
+ if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial)
goto free_strs;
- gadget->strs = strs;
-
/* slp-gadget use max 2 confiuration and NULL termination */
configs = calloc(3, sizeof(*configs));
if (!configs)
@@ -186,37 +135,21 @@ static int alloc_default_gadget(struct usb_gadget **_gadget)
return 0;
free_strs:
- free(strs[0].manufacturer);
- free(strs[0].product);
- free(strs[0].serial);
- free(strs);
-free_gadget:
+ free(gadget->strs.manufacturer);
+ free(gadget->strs.product);
+ free(gadget->strs.serial);
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)
+static int 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;
+ int i, j;
+ int n_configs;
+ struct usb_gadget *gadget;
+ int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */
if (!gadget_id || !_gadget)
return -EINVAL;
@@ -233,31 +166,11 @@ 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:
- n_configs = 1;
- functions[0][0] = USB_FUNCTION_SDB;
- functions[0][1] = 0;
- gadget->attrs.idProduct = 0x685d;
- break;
-
- case USB_FUNCTION_MTP:
+ /* MTP, ACM, SDB */
+ case USB_FUNCTION_MTP | USB_FUNCTION_ACM:
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][1] = USB_FUNCTION_ACM;
functions[0][2] = 0;
gadget->attrs.idProduct = 0x6860;
break;
@@ -271,15 +184,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,14 +195,12 @@ 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;
- gadget->attrs.idProduct = 0x6864;
+ functions[0][1] = 0;
+ gadget->attrs.idProduct = 0x6863;
break;
case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
@@ -307,68 +210,43 @@ 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][0] = USB_FUNCTION_RNDIS;
+ functions[0][1] = USB_FUNCTION_ACM;
+ functions[0][2] = USB_FUNCTION_SDB;
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);
-
- 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;
+ struct usb_configuration *config;
for (i = 0; functions[j][i]; ++i);
n_funcs_in_config = i;
@@ -378,25 +256,110 @@ static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
goto free_configs;
gadget->configs[j] = config;
- config->funcs = calloc(n_funcs_in_config + 1,
- sizeof(void *));
+ 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]);
+ 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_functions:
free_gadget:
- simple_cleanup_gadget(gadget);
+ cleanup_gadget(gadget);
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);
+}
+
+#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, \
+ .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, 0, NULL, 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 */
+};
+
+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;
+}
+
+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;
+}
+
+
EXPORT
int simple_translator_open(struct hw_info *info,
const char *id, struct hw_common **common)
@@ -406,13 +369,24 @@ int simple_translator_open(struct hw_info *info,
if (!info || !common)
return -EINVAL;
- simple_translator = zalloc(sizeof(*simple_translator));
+ simple_translator = calloc(1, 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;
+ simple_translator->id_to_gadget = id_to_gadget;
+ simple_translator->cleanup_gadget = 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]->service = "mtp-responder-dummy";
+ }
*common = &simple_translator->common;
return 0;