diff options
Diffstat (limited to 'hw/usb_gadget_common.c')
-rw-r--r-- | hw/usb_gadget_common.c | 346 |
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; |