usb-gadget: access external symbol using dlsym(), not extern keyword
[platform/hal/backend/device-common.git] / src / usb_gadget / usb_gadget_common.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <errno.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21
22 #include <dlfcn.h>
23
24 #include <libsyscommon/libsystemd.h>
25 #include <libsyscommon/list.h>
26 #include <hal/device/hal-usb_gadget-interface.h>
27
28 #include "usb_gadget.h"
29 #include "hal-backend-common.h"
30
31 static struct usb_function *_available_funcs[];
32
33 /**************************************
34  * Those symbols must be initialized first in deviced
35  *
36  * The usb-gadget source code have been scattered throughout the deviced and device-common.
37  * Because of this, it might have been implemented that totally same data structure on the
38  * both side. To avoid this inefficiency, define/initialize the data structure on the
39  * deviced first, and device-common refer it through dlsym(). The deviced must have
40  * cflag -rdynamic or ldflag --export-dynamic so that the dlopen-ed device-common can refer
41  * those variables with dlsym().
42  *
43  * Accessing symbol in this way would be removed when the usb-gadget of the device-common
44  * is integrated into the deviced.
45  */
46 #include <glib.h>
47 #include <hal/device/hal-usb_gadget-interface.h>
48
49 struct _usb_mode_mapping_table {
50         int          mode_v; /* Integer defined by vconf */
51         unsigned int mode;   /* Bitmap of usb function combination */
52         struct usb_gadget_attrs attrs;
53 };
54 static GList *usb_mode_mapping_table_custom;
55
56 struct service_config {
57         char name[128];
58         int remain_after_disable;
59 };
60 static GList *service_config_list;
61 /**************************************/
62
63 struct usb_function *find_usb_function_by_id(int id);
64
65 static void simple_cleanup_config(struct usb_configuration *config)
66 {
67         if (!config)
68                 return;
69
70         free(config->strs.config_str);
71
72         if (config->funcs)
73                 free(config->funcs);
74
75         free(config);
76 }
77
78 static void cleanup_gadget(struct usb_gadget *gadget)
79 {
80         int i;
81
82         if (!gadget)
83                 return;
84
85         free(gadget->strs.manufacturer);
86         free(gadget->strs.product);
87         free(gadget->strs.serial);
88
89         if (gadget->configs) {
90                 for (i = 0; gadget->configs[i]; ++i)
91                         simple_cleanup_config(gadget->configs[i]);
92
93                 free(gadget->configs);
94         }
95
96         free(gadget);
97 }
98
99 static int alloc_default_config(struct usb_configuration **_config)
100 {
101         struct usb_configuration *config;
102
103         config = calloc(1, sizeof(*config));
104         if (!config)
105                 return -ENOMEM;
106
107         config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
108         config->attrs.MaxPower = DEFAULT_MAX_POWER;
109
110         /* TODO. Here is where to set the string used in config of configfs */
111
112         *_config = config;
113
114         return 0;
115 }
116
117 static int alloc_default_gadget(char *serial, struct usb_gadget **_gadget)
118 {
119         struct usb_gadget *gadget;
120         struct usb_configuration **configs;
121
122         gadget = calloc(1, sizeof(*gadget));
123         if (!gadget)
124                 goto out;
125
126         gadget->attrs.idVendor = DEFAULT_VID;
127         gadget->attrs.idProduct = DEFAULT_PID;
128         gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
129
130         gadget->strs.lang_code = DEFAULT_LANG;
131         gadget->strs.manufacturer = strdup(DEFAULT_MANUFACTURER);
132         gadget->strs.product = strdup(DEFAULT_PRODUCT);
133         gadget->strs.serial = strdup(serial);
134
135         if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial)
136                 goto free_strs;
137
138         /* slp-gadget use max 2 confiuration and NULL termination */
139         configs = calloc(3, sizeof(*configs));
140         if (!configs)
141                 goto free_strs;
142
143         gadget->configs = configs;
144         *_gadget = gadget;
145
146         return 0;
147
148 free_strs:
149         free(gadget->strs.manufacturer);
150         free(gadget->strs.product);
151         free(gadget->strs.serial);
152         free(gadget);
153 out:
154         return -ENOMEM;
155 }
156
157 static int id_to_gadget(struct usb_gadget_id *gadget_id, char *serial, struct usb_gadget **_gadget)
158 {
159         int ret;
160         int i, j;
161         int n_configs;
162         struct usb_gadget *gadget;
163         int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */
164
165         GList *elem;
166         const struct _usb_mode_mapping_table *cm = NULL;
167
168         if (!gadget_id || !serial || !_gadget)
169                 return -EINVAL;
170
171         ret = alloc_default_gadget(serial, &gadget);
172         if (ret)
173                 goto out;
174
175         /* find custom mode */
176         SYS_G_LIST_FOREACH(usb_mode_mapping_table_custom, elem, cm) {
177                 if (cm->mode == gadget_id->function_mask)
178                         break;
179         }
180
181         if (cm) {
182                 int i, j;
183
184                 j = 0;
185                 n_configs = 1;
186                 for (i = 0; i < USB_FUNCTION_IDX_MAX; ++i) {
187                         if (cm->mode & (1 << i))
188                                 functions[0][j++] = (1 << i);
189                 }
190                 functions[0][j] = 0;
191
192                 if (cm->attrs.idVendor)
193                         gadget->attrs.idVendor = cm->attrs.idVendor;
194                 if (cm->attrs.idProduct)
195                         gadget->attrs.idProduct = cm->attrs.idProduct;
196
197         } else {
198                 /*
199                  * Currently all gadgets use inly single configuration but
200                  * slp-gadget is capable to handle two of them
201                  *
202                  * Order of interfaces in configuration is significant
203                  * so in this switch we sort our functions in a correct order
204                  */
205                 switch (gadget_id->function_mask) {
206                         /* MTP, ACM, SDB */
207                         case USB_FUNCTION_MTP | USB_FUNCTION_ACM:
208                                 n_configs = 1;
209                                 functions[0][0] = USB_FUNCTION_MTP;
210                                 functions[0][1] = USB_FUNCTION_ACM;
211                                 functions[0][2] = 0;
212                                 gadget->attrs.idProduct = 0x6860;
213                                 break;
214
215                         case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
216                                 n_configs = 1;
217                                 functions[0][0] = USB_FUNCTION_MTP;
218                                 functions[0][1] = USB_FUNCTION_ACM;
219                                 functions[0][2] = USB_FUNCTION_SDB;
220                                 functions[0][3] = 0;
221                                 gadget->attrs.idProduct = 0x6860;
222                                 break;
223
224                                 /* DIAG */
225                         case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
226                                 n_configs = 1;
227                                 functions[0][0] = USB_FUNCTION_MTP;
228                                 functions[0][1] = USB_FUNCTION_ACM;
229                                 functions[0][2] = USB_FUNCTION_SDB;
230                                 functions[0][3] = USB_FUNCTION_DIAG;
231                                 functions[0][4] = 0;
232                                 gadget->attrs.idProduct = 0x6860;
233                                 break;
234
235                                 /* RNDIS */
236                         case USB_FUNCTION_RNDIS:
237                                 n_configs = 1;
238                                 functions[0][0] = USB_FUNCTION_RNDIS;
239                                 functions[0][1] = 0;
240                                 gadget->attrs.idProduct = 0x6863;
241                                 break;
242
243                         case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
244                                 n_configs = 1;
245                                 functions[0][0] = USB_FUNCTION_RNDIS;
246                                 functions[0][1] = USB_FUNCTION_DIAG;
247                                 functions[0][2] = 0;
248                                 gadget->attrs.idProduct = 0x6864;
249                                 break;
250
251                         case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
252                                 n_configs = 1;
253                                 functions[0][0] = USB_FUNCTION_RNDIS;
254                                 functions[0][1] = USB_FUNCTION_ACM;
255                                 functions[0][2] = USB_FUNCTION_SDB;
256                                 functions[0][3] = 0;
257                                 gadget->attrs.idProduct = 0x6864;
258                                 break;
259
260                                 /* RMNET */
261                         case USB_FUNCTION_DIAG | USB_FUNCTION_RMNET:
262                                 n_configs = 1;
263                                 functions[0][0] = USB_FUNCTION_DIAG;
264                                 functions[0][1] = USB_FUNCTION_RMNET;
265                                 functions[0][2] = 0;
266                                 gadget->attrs.idProduct = 0x685d;
267                                 break;
268
269                                 /* DM */
270                         case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
271                                 n_configs = 1;
272                                 functions[0][0] = USB_FUNCTION_ACM;
273                                 functions[0][1] = USB_FUNCTION_SDB;
274                                 functions[0][2] = USB_FUNCTION_DM;
275                                 functions[0][3] = 0;
276                                 gadget->attrs.idProduct = 0x6860;
277                                 break;
278
279                         default:
280                                 ret = -EINVAL;
281                                 goto free_gadget;
282                 };
283         }
284
285         for (j = 0; j < n_configs; ++j) {
286                 int n_funcs_in_config;
287                 struct usb_configuration *config;
288
289                 for (i = 0; functions[j][i]; ++i);
290                 n_funcs_in_config = i;
291
292                 ret = alloc_default_config(&config);
293                 if (ret)
294                         goto free_configs;
295
296                 gadget->configs[j] = config;
297                 config->funcs = calloc(n_funcs_in_config + 1, sizeof(void *));
298                 if (!config->funcs)
299                         goto free_configs;
300
301                 for (i = 0; functions[j][i]; ++i) {
302                         config->funcs[i] = find_usb_function_by_id(functions[j][i]);
303                         if (!config->funcs[i])
304                                 goto free_configs;
305                 }
306         }
307
308         *_gadget = gadget;
309
310         return 0;
311
312 free_configs:
313 free_gadget:
314         cleanup_gadget(gadget);
315 out:
316         return ret;
317 }
318
319 void rndis_handler(int enable)
320 {
321         if (enable)
322                 (void)systemd_start_unit_wait_started("rndis.service", NULL, -1);
323         else
324                 (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1);
325 }
326
327 #define DEFINE_USB_FUNCTION(_id, _name, _is_functionfs, _service, _handler)  \
328         static struct usb_function _##_name##_function = {                   \
329                 .id = _id,                                                   \
330                 .name = #_name,                                              \
331                 .instance = "default",                                       \
332                 .is_functionfs = _is_functionfs,                             \
333                 .service = _service,                                         \
334                 .remain_after_disable = 0,                                   \
335                 .handler = _handler,                                         \
336         }
337
338 DEFINE_USB_FUNCTION(USB_FUNCTION_MTP,         mtp,         1, "mtp-responder", NULL);
339 DEFINE_USB_FUNCTION(USB_FUNCTION_ACM,         acm,         0, "data-router",   NULL);
340 DEFINE_USB_FUNCTION(USB_FUNCTION_SDB,         sdb,         1, "sdbd",          NULL);
341 DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS,       rndis,       0, "sshd",          rndis_handler);
342 DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG,        diag,        1, "diag",          NULL);
343 DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, 0, NULL,            NULL);
344 DEFINE_USB_FUNCTION(USB_FUNCTION_DM,          dm,          0, NULL,            NULL);
345 DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET,       rmnet,       0, NULL,            NULL);
346
347 #undef DEFINE_USB_FUNCTION
348
349 /* Caution: index order of arrary is important, because simple_translator_open() uses it. */
350 static struct usb_function *_available_funcs[] = {
351         [USB_FUNCTION_IDX_MTP]         = &_mtp_function,
352         [USB_FUNCTION_IDX_ACM]         = &_acm_function,
353         [USB_FUNCTION_IDX_SDB]         = &_sdb_function,
354         [USB_FUNCTION_IDX_RNDIS]       = &_rndis_function,
355         [USB_FUNCTION_IDX_DIAG]        = &_diag_function,
356         [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function,
357         [USB_FUNCTION_IDX_DM]          = &_dm_function,
358         [USB_FUNCTION_IDX_RMNET]       = &_rmnet_function,
359         [USB_FUNCTION_IDX_MAX]         = NULL /* An indicator to end the array */
360 };
361
362 struct usb_function *find_usb_function_by_id(int id)
363 {
364         int i;
365
366         for (i = 0; _available_funcs[i]; i++)
367                 if (_available_funcs[i]->id == id)
368                         return _available_funcs[i];
369
370         return NULL;
371 }
372
373 struct usb_function *find_usb_function_by_name(const char *name)
374 {
375         int i;
376
377         if(!name || !name[0])
378                 return NULL;
379
380         for (i = 0; _available_funcs[i]; i++)
381                 if (!strcmp(name, _available_funcs[i]->name))
382                         return _available_funcs[i];
383
384         return NULL;
385 }
386
387 struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance)
388 {
389         int i;
390
391         if(!name || !name[0] || !instance || !instance[0])
392                 return NULL;
393
394         for (i = 0; _available_funcs[i]; ++i)
395                 if (!strcmp(name, _available_funcs[i]->name) && !strcmp(instance, _available_funcs[i]->instance))
396                         return _available_funcs[i];
397
398         return NULL;
399 }
400
401 static void set_service_config(gpointer data, gpointer udata)
402 {
403         struct service_config *svc = (struct service_config *) data;
404         int i;
405
406         for (i = 0; _available_funcs[i]; ++i) {
407                 if (!strcmp(svc->name, _available_funcs[i]->name)) {
408                         _available_funcs[i]->remain_after_disable = svc->remain_after_disable;
409                         _I("%s: remain_after_disable=%d", svc->name, svc->remain_after_disable);
410                 }
411         }
412 }
413
414 EXPORT
415 int simple_translator_open(hal_backend_usb_gadget_funcs *usb_gadget_funcs)
416 {
417         char *dlerr;
418
419         if (!usb_gadget_funcs)
420                 return -EINVAL;
421
422         dlerror(); // clear any existing dl error
423
424         usb_mode_mapping_table_custom = *(GList **) dlsym(RTLD_DEFAULT, "usb_mode_mapping_table_custom");
425         dlerr = dlerror();
426         if (dlerr) {
427                 _E("%s", dlerr);
428                 return -ENOTSUP;
429         }
430
431         service_config_list = *(GList **) dlsym(RTLD_DEFAULT, "service_config_list");
432         dlerr = dlerror();
433         if (dlerr) {
434                 _E("%s", dlerror());
435                 return -ENOTSUP;
436         }
437
438         /* e.g.
439          * /hal/etc/deviced/usb_gadget.conf
440          *
441          * [SystemdUnit]
442          * Name=diag.service
443          * RemainAfterDisable=yes
444          */
445         g_list_foreach(service_config_list, set_service_config, NULL);
446
447         usb_gadget_funcs->id_to_gadget = id_to_gadget;
448         usb_gadget_funcs->cleanup_gadget = cleanup_gadget;
449
450         /* Use mtp-responder-dummy.socket when there is no mtp-responser.socket.
451          *
452          * The mtp-responder.socket is special in the configfs environment.
453          * If mtp-responder.socket is missing, gadget configuration will fail.
454          * As a result, all usb operations do not work properly.
455          * So in environments that mtp doesn't support, use dummy mtp.
456          */
457         if (access("/usr/lib/systemd/system/mtp-responder.socket", F_OK)) {
458                 _available_funcs[USB_FUNCTION_IDX_MTP]->service = "mtp-responder-dummy";
459         }
460
461         return 0;
462 }
463
464 EXPORT
465 int simple_translator_close(hal_backend_usb_gadget_funcs *usb_gadget_funcs)
466 {
467         return 0;
468 }