usb-gadget: introduce configurable usb-gadget 12/272412/6
authorYoungjae Cho <y0.cho@samsung.com>
Wed, 16 Mar 2022 08:25:33 +0000 (17:25 +0900)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Fri, 18 Mar 2022 07:45:41 +0000 (07:45 +0000)
Change-Id: Iaf2adf68666b1def8dcf6b04707d0f5a3f5fc3e0
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
src/usb/usb-state.c
src/usb/usb.c
src/usb/usb.h

index 17df193..77375c6 100644 (file)
  */
 
 
+#include <string.h>
 #include <vconf.h>
 #include <bundle.h>
 #include <eventsystem.h>
 #include <hal/device/hal-usb_gadget-interface.h>
+#include <libsyscommon/ini-parser.h>
 
 #include "core/log.h"
 #include "apps/apps.h"
@@ -29,6 +31,8 @@
 #include "usb.h"
 #include "usb-debug.h"
 
+#define PATH_USB_GADGET_CONF    "/hal/etc/deviced/usb_gadget.conf"
+
 static int noti_id = -1;
 
 static unsigned int usb_current_mode = USB_FUNCTION_NONE;
@@ -49,6 +53,7 @@ static extcon_usb_state_e usb_connection = USB_DISCONNECTED;
 static const 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;
 } usb_mode_mapping_table[] = {
        /* Hack for performance. In most cases this is the value. */
        {SET_USB_DEFAULT,         USB_FUNCTION_MTP | USB_FUNCTION_ACM},
@@ -68,12 +73,43 @@ static const struct _usb_mode_mapping_table {
        {SET_USB_RNDIS_SDB_ACM,   USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS},
 };
 
+static const int mapping_table_len = sizeof(usb_mode_mapping_table) / sizeof(usb_mode_mapping_table[0]);
+
+/*
+ * Private, custom defined mode mapping.
+ * You can define custom mode_v with mode from /hal/etc/deviced/usb_gadget.conf
+ * A custom mapping precedes the above default mapping if the custom mode_v overlaps
+ * default mode_v.
+ *
+ * Do not declare it with static storage class as it will be exported as dynamic symbol
+ * so that dlopen-ed device-common can refer it.
+ */
+GList *usb_mode_mapping_table_custom;
+
+/*
+ * Do not declare it with static storage class as it will be exported as dynamic symbol
+ * so that dlopen-ed device-common can refer it.
+ */
+struct service_config {
+       char name[128];
+       int remain_after_disable; /* do not stop the service on disabling usb-gadget function */
+};
+GList *service_config_list;
+
 unsigned int get_mode_bitmap_from_vconf(int mode_v)
 {
        int i;
-       int array_len = sizeof(usb_mode_mapping_table)/sizeof(usb_mode_mapping_table[0]);
+       GList *elem;
+       struct _usb_mode_mapping_table *table;
+
+       /* lookup from custom mapping table first */
+       SYS_G_LIST_FOREACH(usb_mode_mapping_table_custom, elem, table) {
+               if (table->mode_v == mode_v)
+                       return table->mode;
+       }
 
-       for (i = 0; i < array_len; i++) {
+       /* and then lookup the default mapping table */
+       for (i = 0; i < mapping_table_len; i++) {
                if (usb_mode_mapping_table[i].mode_v == mode_v)
                        return usb_mode_mapping_table[i].mode;
        }
@@ -84,10 +120,17 @@ unsigned int get_mode_bitmap_from_vconf(int mode_v)
 static int get_mode_vconf_from_bitmap(unsigned int mode)
 {
        int i;
-       int array_len = sizeof(usb_mode_mapping_table)/sizeof(usb_mode_mapping_table[0]);
+       GList *elem;
+       struct _usb_mode_mapping_table *table;
+
+       /* lookup from custom mapping table first */
+       SYS_G_LIST_FOREACH(usb_mode_mapping_table_custom, elem, table) {
+               if (table->mode == mode)
+                       return table->mode_v;
+       }
 
        /* Caution: The order to search the usb_mode_mapping_table must start with a low index. */
-       for (i = 0; i < array_len; i++) {
+       for (i = 0; i < mapping_table_len; i++) {
                if (usb_mode_mapping_table[i].mode == mode)
                        return usb_mode_mapping_table[i].mode_v;
        }
@@ -125,6 +168,139 @@ static void usb_state_send_system_event(int status)
        bundle_free(b);
 }
 
+static void parse_property_systemd_unit(gpointer data, gpointer udata)
+{
+       struct section_property *prop = (struct section_property *) data;
+       struct service_config *svc = (struct service_config *) udata;
+
+       if (MATCH(prop->key, "Service")) {
+               strncpy(svc->name, prop->value, sizeof(svc->name));
+       } else if (MATCH(prop->key, "RemainAfterDisable")) {
+               svc->remain_after_disable = MATCH(prop->value, "yes");
+       }
+}
+
+static unsigned int parse_usb_function(char *fstr)
+{
+       // Parse Function=, e.g., "Function=diag,acm"
+       unsigned int ret = USB_FUNCTION_NONE;
+       char *p, *saveptr;
+
+       if (!fstr)
+               return ret;
+
+       p = strtok_r(fstr, ",", &saveptr);
+       if (!p)
+               return ret;
+
+       do {
+               if (strncasecmp(p, "mtp", sizeof("mtp")) == 0) {
+                       ret |= USB_FUNCTION_MTP;
+               } else if (strncasecmp(p, "acm", sizeof("acm")) == 0) {
+                       ret |= USB_FUNCTION_ACM;
+               } else if(strncasecmp(p, "sdb", sizeof("sdb")) == 0) {
+                       ret |= USB_FUNCTION_SDB;
+               } else if (strncasecmp(p, "rndis", sizeof("rndis")) == 0) {
+                       ret |= USB_FUNCTION_RNDIS;
+               } else if (strncasecmp(p, "diag", sizeof("diag")) == 0) {
+                       ret |= USB_FUNCTION_DIAG;
+               } else if (strncasecmp(p, "conngadget", sizeof("conngadget")) == 0) {
+                       ret |= USB_FUNCTION_CONN_GADGET;
+               } else if (strncasecmp(p, "dm", sizeof("dm")) == 0) {
+                       ret |= USB_FUNCTION_DM;
+               } else if (strncasecmp(p, "rmnet", sizeof("rmnet")) == 0) {
+                       ret |= USB_FUNCTION_RMNET;
+               }
+       } while ((p = strtok_r(NULL, ",", &saveptr)));
+
+       return ret;
+}
+
+static void parse_property_attribute(gpointer data, gpointer udata)
+{
+       struct section_property *prop = (struct section_property *) data;
+       struct _usb_mode_mapping_table *table = (struct _usb_mode_mapping_table *) udata;
+       unsigned int value;
+
+       if (MATCH(prop->key, "Mode")) {
+               sscanf(prop->value, "%d", &table->mode_v);
+       } else if (MATCH(prop->key, "Function")) {
+               table->mode = parse_usb_function(prop->value);
+       } else if (MATCH(prop->key, "bDeviceClass")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.bDeviceClass = (uint8_t) value;
+       } else if (MATCH(prop->key, "bDeviceSubClass")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.bDeviceSubClass = (uint8_t) value;
+       } else if (MATCH(prop->key, "bDeviceProtocol")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.bDeviceProtocol = (uint8_t) value;
+       } else if (MATCH(prop->key, "idVendor")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.idVendor = (uint16_t) value;
+       } else if (MATCH(prop->key, "idProduct")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.idProduct = (uint16_t) value;
+       } else if (MATCH(prop->key, "bcdDevice")) {
+               sscanf(prop->value, "%x", &value);
+               table->attrs.bcdDevice = (uint16_t) value;
+       }
+}
+
+static int load_usb_gadget_config(const struct parse_result *result, void *data)
+{
+       if (MATCH(result->section, "SystemdUnit")) {
+               struct service_config svc = { 0, };
+               void *entry = NULL;
+
+               g_list_foreach(result->props, parse_property_systemd_unit, &svc);
+
+               entry = malloc(sizeof(struct service_config));
+               if (!entry) {
+                       _E("Failed to alloc service config");
+                       return 0;
+               }
+
+               _I("usb-gadget service config: name=%s, remain_after_disable=%d",
+                       svc.name, svc.remain_after_disable);
+               service_config_list = g_list_prepend(service_config_list, memcpy(entry, &svc, sizeof(svc)));
+
+       } else if (MATCH(result->section, "Attribute")) {
+               struct _usb_mode_mapping_table table = { 0, };
+               void *entry = NULL;
+
+               g_list_foreach(result->props, parse_property_attribute, &table);
+
+               // if it hasn't defined mode, use default or pre-defined one
+               if (table.mode == USB_FUNCTION_NONE)
+                       table.mode = get_mode_bitmap_from_vconf(table.mode_v);
+
+               if (table.mode == USB_FUNCTION_INVALID)
+                       return 0;
+
+               if (table.mode_v >= SET_USB_NONE && table.mode_v <= SET_USB_RNDIS_SDB_ACM)
+                       _W("The custom mode=%d replaces the predefined usb-gadget configuration", table.mode_v);
+
+               entry = malloc(sizeof(struct _usb_mode_mapping_table));
+               if (!entry) {
+                       _E("Failed to alloc mapping table");
+                       return 0;
+               }
+
+               _I("Custom usb-gadget: mode=%d, function=%#x, idVendor=%#x, idProduct=%#x",
+                       table.mode_v, table.mode, table.attrs.idVendor, table.attrs.idProduct);
+
+               usb_mode_mapping_table_custom = g_list_prepend(usb_mode_mapping_table_custom, memcpy(entry, &table, sizeof(table)));
+       }
+
+       return 0;
+}
+
+void usb_state_load_custom_mode(void)
+{
+       libsys_config_parse_by_section(PATH_USB_GADGET_CONF, load_usb_gadget_config, NULL);
+}
+
 void usb_state_retrieve_selected_mode(void)
 {
        int mode_v;
index d1f9198..6792310 100644 (file)
@@ -283,6 +283,7 @@ static void usb_init(void *data)
 {
        int ret;
 
+       usb_state_load_custom_mode();
        usb_state_retrieve_selected_mode();
 
        ret = hal_device_usb_gadget_get_backend();
index 204cadb..0e30b2e 100644 (file)
@@ -28,6 +28,8 @@
 
 int usb_dbus_init(void);
 
+void usb_state_load_custom_mode(void);
+
 int usb_change_mode(unsigned int mode, bool change_debug_mode);
 void usb_state_retrieve_selected_mode(void);
 unsigned int get_mode_bitmap_from_vconf(int mode_v);