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