4 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <hw/usb_client.h>
20 #include <hw/systemd.h>
21 #include <hw/shared.h>
28 #define zalloc(amount) calloc(1, amount)
30 #define MAX_GADGET_STR_LEN 256
33 #define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0"
35 /* Device descriptor values */
36 #define LEGACY_ID_VENDOR_PATH LEGACY_ROOTPATH"/idVendor"
37 #define LEGACY_ID_PRODUCT_PATH LEGACY_ROOTPATH"/idProduct"
38 #define LEGACY_BCD_DEVICE_PATH LEGACY_ROOTPATH"/bcdDevice"
39 #define LEGACY_CLASS_PATH LEGACY_ROOTPATH"/bDeviceClass"
40 #define LEGACY_SUBCLASS_PATH LEGACY_ROOTPATH"/bDeviceSubClass"
41 #define LEGACY_PROTOCOL_PATH LEGACY_ROOTPATH"/bDeviceProtocol"
44 #define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer"
45 #define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct"
46 #define LEGACY_ISERIAL_PATH LEGACY_ROOTPATH"/iSerial"
48 /* Functions in each config */
49 #define LEGACY_CONFIG_1_PATH LEGACY_ROOTPATH"/funcs_fconf"
50 #define LEGACY_CONFIG_2_PATH LEGACY_ROOTPATH"/funcs_sconf"
51 /* should be single char */
52 #define LEGACY_FUNC_SEP ","
55 #define LEGACY_ENABLE_PATH LEGACY_ROOTPATH"/enable"
56 #define LEGACY_ENABLE "1"
57 #define LEGACY_DISABLE "0"
59 #define LEGACY_BMATTRIBUTES ((1 << 7) | (1 << 6))
60 #define LEGACY_MAX_POWER 500
62 /* +5 to be always big enough */
63 #define INT_BUF_SIZE (sizeof(int)*8 + 5)
66 #define EXPORT __attribute__ ((visibility("default")))
69 static int get_int_from_file(char *path, int *_val, int base)
71 char buf[INT_BUF_SIZE];
76 ret = sys_get_str(path, buf, sizeof(buf));
80 val = strtol(buf, &endptr, base);
81 if (val == LONG_MIN || val == LONG_MAX ||
82 buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n')
90 static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget)
94 /* We assume that values received from kernel will be valid */
95 #define GET_VALUE_FROM_SYSFS(path, field, type, base) \
97 ret = get_int_from_file(path, &val, base); \
101 gadget->attrs.field = (type)val; \
104 GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t, 0);
105 GET_VALUE_FROM_SYSFS(LEGACY_SUBCLASS_PATH, bDeviceSubClass, uint8_t, 0);
106 GET_VALUE_FROM_SYSFS(LEGACY_PROTOCOL_PATH, bDeviceProtocol, uint8_t, 0);
107 GET_VALUE_FROM_SYSFS(LEGACY_ID_VENDOR_PATH, idVendor, uint16_t, 16);
108 GET_VALUE_FROM_SYSFS(LEGACY_ID_PRODUCT_PATH, idProduct, uint16_t, 16);
109 GET_VALUE_FROM_SYSFS(LEGACY_BCD_DEVICE_PATH, bcdDevice, uint16_t, 0);
110 #undef GET_VALUE_FROM_SYSFS
112 #define GET_STRING_FROM_SYSFS(path, field) \
114 char buf[MAX_GADGET_STR_LEN]; \
116 ret = sys_get_str(path, buf, sizeof(buf)); \
120 gadget->strs[0].field = strdup(buf); \
121 if (!gadget->strs[0].field) { \
127 GET_STRING_FROM_SYSFS(LEGACY_IMANUFACTURER_PATH, manufacturer);
128 GET_STRING_FROM_SYSFS(LEGACY_IPRODUCT_PATH, product);
129 GET_STRING_FROM_SYSFS(LEGACY_ISERIAL_PATH, serial);
130 #undef GET_STRING_FROM_SYSFS
135 free(gadget->strs[0].product);
137 free(gadget->strs[0].manufacturer);
142 static int legacy_find_func(const char *name)
146 for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
147 if (!strcmp(name, _available_funcs[i]->name))
153 static struct usb_function *legacy_find_func_in_gadget(
154 struct usb_gadget *gadget, const char *name)
158 for (i = 0; gadget->funcs[i]; ++i)
159 if (!strcmp(name, gadget->funcs[i]->name))
160 return gadget->funcs[i];
164 static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config)
166 struct usb_configuration *config;
168 config = zalloc(sizeof(*config));
172 config->strs = calloc(1, sizeof(*config->strs));
176 config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs));
181 * We cannot read correct values
182 * so assume that they are always default
184 config->attrs.bmAttributs = LEGACY_BMATTRIBUTES;
185 config->attrs.MaxPower = LEGACY_MAX_POWER;
198 static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname,
199 struct usb_function **_func)
201 struct usb_function *func;
204 ret = legacy_find_func(fname);
208 ret = _available_funcs[ret]->clone(_available_funcs[ret], &func);
216 static int legacy_read_config(struct usb_gadget *gadget,
218 struct usb_configuration **_config)
220 struct usb_configuration *config;
221 char buf[MAX_GADGET_STR_LEN];
224 char *sep = LEGACY_FUNC_SEP;
230 ret = sys_get_str(cpath, buf, sizeof(buf));
235 if (buf[0] == '\0' || buf[0] == '\n')
238 /* count number of functions in this config */
240 for (i = 0; buf[i] != '\0'; ++i) {
241 if (buf[i] == sep[0])
243 if (buf[i] == '\n') /* buf ends with it */
247 ret = legacy_alloc_config(f_cnt, &config);
251 for (g_f_idx = 0; gadget->funcs[g_f_idx]; ++g_f_idx);
254 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
255 struct usb_function *func;
257 func = legacy_find_func_in_gadget(gadget, fname);
259 /* new function not added yet to gadget */
260 ret = legacy_alloc_new_func(gadget, fname, &func);
264 gadget->funcs[g_f_idx++] = func;
267 config->funcs[f_idx++] = func;
279 static int legacy_get_current_gadget(struct usb_client *usb,
280 struct usb_gadget **_gadget)
282 struct usb_gadget *gadget;
283 struct usb_gadget_strings *strs;
284 struct usb_configuration **configs;
285 struct usb_function **funcs;
289 gadget = zalloc(sizeof(*gadget));
293 strs = calloc(2, sizeof(*strs));
297 strs[0].lang_code = 0x409;
301 ret = legacy_read_gadget_attrs_strs(gadget);
305 /* There will be no more functions than bits in int */
306 funcs = calloc(MAX_FUNCS, sizeof(*funcs));
308 goto free_strs_with_content;
310 gadget->funcs = funcs;
312 /* slp-gadget use max 2 confiuration and NULL termination */
313 configs = calloc(3, sizeof(*configs));
317 gadget->configs = configs;
319 ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0);
323 ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1);
331 free(configs[0]->funcs);
332 free(configs[0]->strs);
336 for (i = 0; gadget->funcs[i]; ++i)
337 gadget->funcs[i]->free_func(gadget->funcs[i]);
340 free_strs_with_content:
341 free(gadget->strs[0].manufacturer);
342 free(gadget->strs[0].product);
343 free(gadget->strs[0].serial);
352 static bool legacy_is_function_supported(struct usb_client *usb,
353 struct usb_function *func)
359 * Instead of only checking whether we know this function
360 * we should also parse sysfs to check if it is build into
363 ret = legacy_find_func(func->name);
368 static bool legacy_is_gadget_supported(struct usb_client *usb,
369 struct usb_gadget *gadget)
373 if (!gadget || !gadget->configs || !gadget->funcs)
378 * Here is a good place to ensure that serial is immutable
381 /* only strings in US_en are allowed */
382 if (gadget->strs[0].lang_code != 0x409 ||
383 gadget->strs[1].lang_code)
387 for (j = 0; gadget->configs[j]; ++j) {
388 struct usb_configuration *config = gadget->configs[j];
390 if (config->strs && config->strs[0].lang_code)
396 for (i = 0; config->funcs[i]; ++i)
397 if (!legacy_is_function_supported(usb, config->funcs[i]))
407 /* TODO. Maybe move this to sys ? */
408 static int legacy_set_int_hex(char *path, int val)
410 char buf[MAX_GADGET_STR_LEN];
416 snprintf(buf, sizeof(buf), "%x", val);
417 r = sys_set_str(path, buf);
424 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
428 ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
432 ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
436 ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
440 ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
444 ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
448 ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
453 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
459 * Here is a good place to ensure that serial is immutable
462 if (strs->manufacturer) {
463 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH,
470 ret = sys_set_str(LEGACY_IPRODUCT_PATH,
479 static int legacy_set_gadget_config(char *cpath,
480 struct usb_configuration *config)
482 char buf[MAX_GADGET_STR_LEN];
483 int left = sizeof(buf);
494 for (i = 0; config->funcs[i]; ++i) {
495 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
496 config->funcs[i]->name);
504 /* eliminate last separator */
508 return sys_set_str(cpath, buf);
511 static int legacy_reconfigure_gadget(struct usb_client *usb,
512 struct usb_gadget *gadget)
516 if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget))
519 ret = legacy_set_gadget_attrs(&gadget->attrs);
524 ret = legacy_set_gadget_strs(gadget->strs + 0);
529 ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
533 ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
538 static int legacy_enable(struct usb_client *usb)
542 struct usb_gadget *gadget;
543 struct usb_function_with_service *fws;
545 ret = sys_set_str(LEGACY_ENABLE_PATH,
550 ret = legacy_get_current_gadget(usb, &gadget);
554 for (i = 0; gadget->funcs[i]; ++i) {
555 if (gadget->funcs[i]->function_group !=
556 USB_FUNCTION_GROUP_WITH_SERVICE)
559 fws = container_of(gadget->funcs[i],
560 struct usb_function_with_service, func);
561 ret = systemd_start_service(fws->service);
569 if (gadget->funcs[i]->function_group !=
570 USB_FUNCTION_GROUP_WITH_SERVICE)
573 fws = container_of(gadget->funcs[i],
574 struct usb_function_with_service, func);
575 systemd_stop_service(fws->service);
579 sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
583 static int legacy_disable(struct usb_client *usb)
587 struct usb_gadget *gadget;
588 struct usb_function_with_service *fws;
590 ret = legacy_get_current_gadget(usb, &gadget);
594 for (i = 0; gadget->funcs[i]; ++i) {
595 if (gadget->funcs[i]->function_group != USB_FUNCTION_GROUP_WITH_SERVICE)
598 fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
599 ret = systemd_stop_service(fws->service);
604 return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
607 static void legacy_free_config(struct usb_configuration *config)
615 for (i = 0; config->strs[i].lang_code; ++i)
616 free(config->strs[i].config_str);
622 * Each function will be free later,
623 * for now we cleanup only pointers.
631 static void legacy_free_gadget(struct usb_gadget *gadget)
639 for (i = 0; gadget->strs[i].lang_code; ++i) {
640 free(gadget->strs[i].manufacturer);
641 free(gadget->strs[i].product);
642 free(gadget->strs[i].serial);
647 if (gadget->configs) {
648 for (i = 0; gadget->configs[i]; ++i)
649 legacy_free_config(gadget->configs[i]);
651 free(gadget->configs);
655 for (i = 0; gadget->funcs[i]; ++i)
656 gadget->funcs[i]->free_func(gadget->funcs[i]);
663 int hw_legacy_gadget_open(struct hw_info *info,
664 const char *id, struct hw_common **common)
666 struct usb_client *legacy;
668 if (!info || !common)
671 /* check if slp usb gadget exists */
672 if (access("/sys/class/usb_mode/usb0/enable", F_OK))
675 legacy = zalloc(sizeof(*legacy));
679 legacy->common.info = info;
680 legacy->get_current_gadget = legacy_get_current_gadget;
681 legacy->reconfigure_gadget = legacy_reconfigure_gadget;
682 legacy->is_gadget_supported = legacy_is_gadget_supported;
683 legacy->is_function_supported = legacy_is_function_supported;
684 legacy->enable = legacy_enable;
685 legacy->disable = legacy_disable;
686 legacy->free_gadget = legacy_free_gadget;
688 *common = &legacy->common;
693 int hw_legacy_gadget_close(struct hw_common *common)
695 struct usb_client *legacy;
700 legacy = container_of(common, struct usb_client,