fab8ea1e61d785f4b42b6e03d5acba61d2ce1e1a
[platform/core/system/libdevice-node.git] / hw / usb_client_common.c
1 /*
2  * libdevice-node
3  *
4  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <hw/usb_client.h>
20 #include <hw/shared.h>
21
22 #include <limits.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <libsyscommon/dbus-systemd.h>
28
29 #define zalloc(amount) calloc(1, amount)
30
31 #define MAX_GADGET_STR_LEN 256
32 #define MAX_FUNCS 32
33
34 #define LEGACY_ROOTPATH        "/sys/class/usb_mode/usb0"
35
36 /* Device descriptor values */
37 #define LEGACY_ID_VENDOR_PATH       LEGACY_ROOTPATH"/idVendor"
38 #define LEGACY_ID_PRODUCT_PATH      LEGACY_ROOTPATH"/idProduct"
39 #define LEGACY_BCD_DEVICE_PATH      LEGACY_ROOTPATH"/bcdDevice"
40 #define LEGACY_CLASS_PATH           LEGACY_ROOTPATH"/bDeviceClass"
41 #define LEGACY_SUBCLASS_PATH        LEGACY_ROOTPATH"/bDeviceSubClass"
42 #define LEGACY_PROTOCOL_PATH        LEGACY_ROOTPATH"/bDeviceProtocol"
43
44 /* Strings */
45 #define LEGACY_IMANUFACTURER_PATH   LEGACY_ROOTPATH"/iManufacturer"
46 #define LEGACY_IPRODUCT_PATH        LEGACY_ROOTPATH"/iProduct"
47 #define LEGACY_ISERIAL_PATH         LEGACY_ROOTPATH"/iSerial"
48
49 /* Functions in each config */
50 #define LEGACY_CONFIG_1_PATH        LEGACY_ROOTPATH"/funcs_fconf"
51 #define LEGACY_CONFIG_2_PATH        LEGACY_ROOTPATH"/funcs_sconf"
52 /* should be single char */
53 #define LEGACY_FUNC_SEP             ","
54
55 /* ON/OFF switch */
56 #define LEGACY_ENABLE_PATH          LEGACY_ROOTPATH"/enable"
57 #define LEGACY_ENABLE               "1"
58 #define LEGACY_DISABLE              "0"
59
60 #define LEGACY_BMATTRIBUTES ((1 << 7) | (1 << 6))
61 #define LEGACY_MAX_POWER 500
62
63 /* +5 to be always big enough */
64 #define INT_BUF_SIZE (sizeof(int)*8 + 5)
65
66 #ifndef EXPORT
67 #define EXPORT  __attribute__ ((visibility("default")))
68 #endif
69
70 static void legacy_free_gadget(struct usb_gadget *gadget);
71
72 static int get_int_from_file(char *path, int *_val, int base)
73 {
74         char buf[INT_BUF_SIZE];
75         char *endptr;
76         long int val;
77         int ret;
78
79         ret = sys_get_str(path, buf, sizeof(buf));
80         if (ret)
81                 return ret;
82
83         val = strtol(buf, &endptr, base);
84         if (val == LONG_MIN || val == LONG_MAX ||
85             buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n')
86             || val >= INT_MAX)
87                 return -EINVAL;
88
89         *_val = (int)val;
90         return 0;
91 }
92
93 static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget)
94 {
95         int val;
96         int ret;
97         /* We assume that values received from kernel will be valid */
98 #define GET_VALUE_FROM_SYSFS(path, field, type, base)   \
99         do {                                            \
100                 ret = get_int_from_file(path, &val, base);      \
101                 if (ret)                                \
102                         return ret;                     \
103                                                         \
104                 gadget->attrs.field = (type)val;        \
105         } while (0)
106
107         GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t, 0);
108         GET_VALUE_FROM_SYSFS(LEGACY_SUBCLASS_PATH, bDeviceSubClass, uint8_t, 0);
109         GET_VALUE_FROM_SYSFS(LEGACY_PROTOCOL_PATH, bDeviceProtocol, uint8_t, 0);
110         GET_VALUE_FROM_SYSFS(LEGACY_ID_VENDOR_PATH, idVendor, uint16_t, 16);
111         GET_VALUE_FROM_SYSFS(LEGACY_ID_PRODUCT_PATH, idProduct, uint16_t, 16);
112         GET_VALUE_FROM_SYSFS(LEGACY_BCD_DEVICE_PATH, bcdDevice, uint16_t, 0);
113 #undef GET_VALUE_FROM_SYSFS
114
115 #define GET_STRING_FROM_SYSFS(path, field)                      \
116         do {                                                    \
117                 char buf[MAX_GADGET_STR_LEN];                   \
118                                                                 \
119                 ret = sys_get_str(path, buf, sizeof(buf));      \
120                 if (ret)                                        \
121                         goto err_##field;                       \
122                                                                 \
123                 gadget->strs[0].field = strdup(buf);            \
124                 if (!gadget->strs[0].field) {                   \
125                         ret = -ENOMEM;                          \
126                         goto err_##field;                       \
127                 }                                               \
128         } while (0)
129
130         GET_STRING_FROM_SYSFS(LEGACY_IMANUFACTURER_PATH, manufacturer);
131         GET_STRING_FROM_SYSFS(LEGACY_IPRODUCT_PATH, product);
132         GET_STRING_FROM_SYSFS(LEGACY_ISERIAL_PATH, serial);
133 #undef GET_STRING_FROM_SYSFS
134
135         return 0;
136
137 err_serial:
138         free(gadget->strs[0].product);
139 err_product:
140         free(gadget->strs[0].manufacturer);
141 err_manufacturer:
142         return ret;
143 }
144
145 static int legacy_find_func(const char *name)
146 {
147         int i;
148
149         for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
150                 if (!strcmp(name, _available_funcs[i]->name))
151                         return i;
152
153         return -1;
154 }
155
156 static struct usb_function *legacy_find_func_in_gadget(
157         struct usb_gadget *gadget, const char *name)
158 {
159         int i;
160
161         for (i = 0; gadget->funcs[i]; ++i)
162                 if (!strcmp(name, gadget->funcs[i]->name))
163                         return gadget->funcs[i];
164         return NULL;
165 }
166
167 static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config)
168 {
169         struct usb_configuration *config;
170
171         config = zalloc(sizeof(*config));
172         if (!config)
173                 goto out;
174
175         config->strs = calloc(1, sizeof(*config->strs));
176         if (!config->strs)
177                 goto free_config;
178
179         config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs));
180         if (!config->funcs)
181                 goto free_strs;
182
183         /*
184          * We cannot read correct values
185          * so assume that they are always default
186          */
187         config->attrs.bmAttributs = LEGACY_BMATTRIBUTES;
188         config->attrs.MaxPower = LEGACY_MAX_POWER;
189
190         *_config = config;
191
192         return 0;
193 free_strs:
194         free(config->strs);
195 free_config:
196         free(config);
197 out:
198         return -ENOMEM;
199 }
200
201 static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname,
202                                  struct usb_function **_func)
203 {
204         struct usb_function *func;
205         int ret;
206
207         ret = legacy_find_func(fname);
208         if (ret < 0)
209                 return -ENOTSUP;
210
211         ret = _available_funcs[ret]->clone(_available_funcs[ret], &func);
212         if (ret)
213                 return ret;
214
215         *_func = func;
216         return 0;
217 }
218
219 static int legacy_read_config(struct usb_gadget *gadget,
220                               char *cpath,
221                               struct usb_configuration **_config)
222 {
223         struct usb_configuration *config;
224         char buf[MAX_GADGET_STR_LEN];
225         char *begin = buf;
226         char *fname;
227         char *sep = LEGACY_FUNC_SEP;
228         int i, f_cnt;
229         int f_idx;
230         int g_f_idx;
231         int ret;
232
233         ret = sys_get_str(cpath, buf, sizeof(buf));
234         if (ret)
235                 return ret;
236
237         /* Empty */
238         if (buf[0] == '\0' || buf[0] == '\n')
239                 return 0;
240
241         /* count number of functions in this config */
242         f_cnt = 1;
243         for (i = 0; buf[i] != '\0'; ++i) {
244                 if (buf[i] == sep[0])
245                         ++f_cnt;
246                 if (buf[i] == '\n')  /* buf ends with it */
247                         buf[i] = 0;
248         }
249
250         ret = legacy_alloc_config(f_cnt, &config);
251         if (ret)
252                 return ret;
253
254         for (g_f_idx = 0; gadget->funcs[g_f_idx]; ++g_f_idx);
255
256         f_idx = 0;
257         for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
258                 struct usb_function *func;
259
260                 func = legacy_find_func_in_gadget(gadget, fname);
261                 if (!func) {
262                         /* new function not added yet to gadget */
263                         ret = legacy_alloc_new_func(gadget, fname, &func);
264                         if (ret)
265                                 goto free_config;
266
267                         gadget->funcs[g_f_idx++] = func;
268                 }
269
270                 config->funcs[f_idx++] = func;
271         }
272
273         *_config = config;
274         return 0;
275 free_config:
276         free(config->strs);
277         free(config->funcs);
278         free(config);
279         return ret;
280 }
281
282 static int legacy_get_current_gadget(struct usb_client *usb,
283                                      struct usb_gadget **_gadget)
284 {
285         struct usb_gadget *gadget;
286         struct usb_gadget_strings *strs;
287         struct usb_configuration **configs;
288         struct usb_function **funcs;
289         int i;
290         int ret = -ENOMEM;
291
292         gadget = zalloc(sizeof(*gadget));
293         if (!gadget)
294                 goto out;
295
296         strs = calloc(2, sizeof(*strs));
297         if (!strs)
298                 goto free_gadget;
299
300         strs[0].lang_code = 0x409;
301
302         gadget->strs = strs;
303
304         ret = legacy_read_gadget_attrs_strs(gadget);
305         if (ret)
306                 goto free_strs;
307
308         /* There will be no more functions than bits in int */
309         funcs = calloc(MAX_FUNCS, sizeof(*funcs));
310         if (!funcs)
311                 goto free_strs_with_content;
312
313         gadget->funcs = funcs;
314
315         /* slp-gadget use max 2 confiuration and NULL termination */
316         configs = calloc(3, sizeof(*configs));
317         if (!configs)
318                 goto free_funcs;
319
320         gadget->configs = configs;
321
322         ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0);
323         if (ret)
324                 goto free_configs;
325
326         ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1);
327         if (ret)
328                 goto free_config_1;
329
330         *_gadget = gadget;
331         return 0;
332
333 free_config_1:
334         free(configs[0]->funcs);
335         free(configs[0]->strs);
336         free(configs[0]);
337 free_configs:
338         free(configs);
339         for (i = 0; gadget->funcs[i]; ++i)
340                 gadget->funcs[i]->free_func(gadget->funcs[i]);
341 free_funcs:
342         free(funcs);
343 free_strs_with_content:
344         free(gadget->strs[0].manufacturer);
345         free(gadget->strs[0].product);
346         free(gadget->strs[0].serial);
347 free_strs:
348         free(gadget->strs);
349 free_gadget:
350         free(gadget);
351 out:
352         return ret;
353 }
354
355 static bool legacy_is_function_supported(struct usb_client *usb,
356                                          struct usb_function *func)
357 {
358         int ret;
359
360         /*
361          * TODO
362          * Instead of only checking whether we know this function
363          * we should also parse sysfs to check if it is build into
364          * slp-gadget.
365          */
366         ret = legacy_find_func(func->name);
367
368         return ret >= 0;
369 }
370
371 static bool legacy_is_gadget_supported(struct usb_client *usb,
372                                        struct usb_gadget *gadget)
373 {
374         int i, j;
375
376         if (!gadget || !gadget->configs || !gadget->funcs)
377                 return false;
378
379         /*
380          * TODO
381          * Here is a good place to ensure that serial is immutable
382          */
383         if (gadget->strs) {
384                 /* only strings in US_en are allowed */
385                 if (gadget->strs[0].lang_code != 0x409 ||
386                     gadget->strs[1].lang_code)
387                         return false;
388         }
389
390         for (j = 0; gadget->configs[j]; ++j) {
391                 struct usb_configuration *config = gadget->configs[j];
392
393                 if (config->strs && config->strs[0].lang_code)
394                         return false;
395
396                 if (!config->funcs)
397                         return false;
398
399                 for (i = 0; config->funcs[i]; ++i)
400                         if (!legacy_is_function_supported(usb, config->funcs[i]))
401                                 return false;
402         }
403
404         if (j == 0 || j > 2)
405                 return false;
406
407         return true;
408 }
409
410 /* TODO. Maybe move this to sys ? */
411 static int legacy_set_int_hex(char *path, int val)
412 {
413         char buf[MAX_GADGET_STR_LEN];
414         int r;
415
416         if (!path)
417                 return -EINVAL;
418
419         snprintf(buf, sizeof(buf), "%x", val);
420         r = sys_set_str(path, buf);
421         if (r < 0)
422                 return r;
423
424         return 0;
425 }
426
427 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
428 {
429         int ret;
430
431         ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
432         if (ret)
433                 return ret;
434
435         ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
436         if (ret)
437                 return ret;
438
439         ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
440         if (ret)
441                 return ret;
442
443         ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
444         if (ret)
445                 return ret;
446
447         ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
448         if (ret)
449                 return ret;
450
451         ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
452
453         return ret;
454 }
455
456 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
457 {
458         int ret = 0;
459
460         /*
461          * TODO
462          * Here is a good place to ensure that serial is immutable
463          */
464
465         if (strs->manufacturer) {
466                 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH,
467                                   strs->manufacturer);
468                 if (ret)
469                         return ret;
470         }
471
472         if (strs->product) {
473                 ret = sys_set_str(LEGACY_IPRODUCT_PATH,
474                                   strs->product);
475                 if (ret)
476                         return ret;
477         }
478
479         return ret;
480 }
481
482 static int legacy_set_gadget_config(char *cpath,
483                                     struct usb_configuration *config)
484 {
485         char buf[MAX_GADGET_STR_LEN];
486         int left = sizeof(buf);
487         char *pos = buf;
488         int ret;
489         int i;
490
491         if (!config) {
492                 buf[0] = '\n';
493                 buf[1] = '\0';
494                 goto empty_config;
495         }
496
497         for (i = 0; config->funcs[i]; ++i) {
498                 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
499                                config->funcs[i]->name);
500                 if (ret >= left)
501                         return -EOVERFLOW;
502
503                 pos += ret;
504                 left -= ret;
505         }
506
507         /* eliminate last separator */
508         *(pos - 1) = '\0';
509
510 empty_config:
511         return sys_set_str(cpath, buf);
512 }
513
514 static int legacy_reconfigure_gadget(struct usb_client *usb,
515                                      struct usb_gadget *gadget)
516 {
517         int ret;
518
519         if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget))
520                 return -EINVAL;
521
522         ret = legacy_set_gadget_attrs(&gadget->attrs);
523         if (ret)
524                 return ret;
525
526         if (gadget->strs) {
527                 ret = legacy_set_gadget_strs(gadget->strs + 0);
528                 if (ret)
529                         return ret;
530         }
531
532         ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
533         if (ret)
534                 return ret;
535
536         ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
537
538         return ret;
539 }
540
541 static int legacy_enable(struct usb_client *usb)
542 {
543         int ret;
544         int i;
545         struct usb_gadget *gadget;
546         struct usb_function_with_service *fws;
547
548         ret = sys_set_str(LEGACY_ENABLE_PATH,
549                            LEGACY_ENABLE);
550         if (ret < 0)
551                 return ret;
552
553         ret = legacy_get_current_gadget(usb, &gadget);
554         if (ret < 0)
555                 goto disable_gadget;
556
557         for (i = 0; gadget->funcs[i]; ++i) {
558                 if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
559                         continue;
560
561                 fws = container_of(gadget->funcs[i],
562                                    struct usb_function_with_service, func);
563                 systemd_start_unit_wait_started(fws->service, ".service", -1);
564         }
565
566         legacy_free_gadget(gadget);
567         return 0;
568
569 disable_gadget:
570         sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
571         return ret;
572 }
573
574 static int legacy_disable(struct usb_client *usb)
575 {
576         int ret;
577         int i;
578         struct usb_gadget *gadget;
579         struct usb_function_with_service *fws;
580
581         ret = legacy_get_current_gadget(usb, &gadget);
582         if (ret < 0)
583                 return ret;
584
585         for (i = 0; gadget->funcs[i]; ++i) {
586                 if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
587                         continue;
588
589                 fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
590                 ret = systemd_stop_unit_wait_stopped(fws->service, ".service", -1);
591                 if (ret < 0)
592                         goto free_gadget;
593         }
594
595         ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
596
597 free_gadget:
598         legacy_free_gadget(gadget);
599         return ret;
600 }
601
602 static void legacy_free_config(struct usb_configuration *config)
603 {
604         int i;
605
606         if (!config)
607                 return;
608
609         if (config->strs) {
610                 for (i = 0; config->strs[i].lang_code; ++i)
611                         free(config->strs[i].config_str);
612
613                 free(config->strs);
614         }
615
616         /*
617          * Each function will be free later,
618          * for now we cleanup only pointers.
619          */
620         if (config->funcs)
621                 free(config->funcs);
622
623         free(config);
624 }
625
626 static void legacy_free_gadget(struct usb_gadget *gadget)
627 {
628         int i;
629
630         if (!gadget)
631                 return;
632
633         if (gadget->strs) {
634                 for (i = 0; gadget->strs[i].lang_code; ++i) {
635                         free(gadget->strs[i].manufacturer);
636                         free(gadget->strs[i].product);
637                         free(gadget->strs[i].serial);
638                 }
639                 free(gadget->strs);
640         }
641
642         if (gadget->configs) {
643                 for (i = 0; gadget->configs[i]; ++i)
644                         legacy_free_config(gadget->configs[i]);
645
646                 free(gadget->configs);
647         }
648
649         if (gadget->funcs) {
650                 for (i = 0; gadget->funcs[i]; ++i)
651                         gadget->funcs[i]->free_func(gadget->funcs[i]);
652
653                 free(gadget->funcs);
654         }
655
656         free(gadget);
657 }
658
659 EXPORT
660 int hw_legacy_gadget_open(struct hw_info *info,
661                 const char *id, struct hw_common **common)
662 {
663         struct usb_client *legacy;
664
665         if (!info || !common)
666                 return -EINVAL;
667
668         /* check if slp usb gadget exists */
669         if (access("/sys/class/usb_mode/usb0/enable", F_OK))
670                 return -ENOENT;
671
672         legacy = zalloc(sizeof(*legacy));
673         if (!legacy)
674                 return -ENOMEM;
675
676         legacy->common.info = info;
677         legacy->get_current_gadget = legacy_get_current_gadget;
678         legacy->reconfigure_gadget = legacy_reconfigure_gadget;
679         legacy->is_gadget_supported = legacy_is_gadget_supported;
680         legacy->is_function_supported = legacy_is_function_supported;
681         legacy->enable = legacy_enable;
682         legacy->disable = legacy_disable;
683         legacy->free_gadget = legacy_free_gadget;
684
685         *common = &legacy->common;
686         return 0;
687 }
688
689 EXPORT
690 int hw_legacy_gadget_close(struct hw_common *common)
691 {
692         struct usb_client *legacy;
693
694         if (!common)
695                 return -EINVAL;
696
697         legacy = container_of(common, struct usb_client,
698                                          common);
699
700         free(legacy);
701         return 0;
702 }