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/shared.h>
27 #include <libsyscommon/dbus-systemd.h>
29 #define zalloc(amount) calloc(1, amount)
31 #define MAX_GADGET_STR_LEN 256
34 #define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0"
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"
45 #define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer"
46 #define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct"
47 #define LEGACY_ISERIAL_PATH LEGACY_ROOTPATH"/iSerial"
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 ","
56 #define LEGACY_ENABLE_PATH LEGACY_ROOTPATH"/enable"
57 #define LEGACY_ENABLE "1"
58 #define LEGACY_DISABLE "0"
60 #define LEGACY_BMATTRIBUTES ((1 << 7) | (1 << 6))
61 #define LEGACY_MAX_POWER 500
63 /* +5 to be always big enough */
64 #define INT_BUF_SIZE (sizeof(int)*8 + 5)
67 #define EXPORT __attribute__ ((visibility("default")))
70 static void legacy_free_gadget(struct usb_gadget *gadget);
72 static int get_int_from_file(char *path, int *_val, int base)
74 char buf[INT_BUF_SIZE];
79 ret = sys_get_str(path, buf, sizeof(buf));
83 val = strtol(buf, &endptr, base);
84 if (val == LONG_MIN || val == LONG_MAX ||
85 buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n')
93 static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget)
97 /* We assume that values received from kernel will be valid */
98 #define GET_VALUE_FROM_SYSFS(path, field, type, base) \
100 ret = get_int_from_file(path, &val, base); \
104 gadget->attrs.field = (type)val; \
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
115 #define GET_STRING_FROM_SYSFS(path, field) \
117 char buf[MAX_GADGET_STR_LEN]; \
119 ret = sys_get_str(path, buf, sizeof(buf)); \
123 gadget->strs[0].field = strdup(buf); \
124 if (!gadget->strs[0].field) { \
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
138 free(gadget->strs[0].product);
140 free(gadget->strs[0].manufacturer);
145 static int legacy_find_func(const char *name)
149 for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
150 if (!strcmp(name, _available_funcs[i]->name))
156 static struct usb_function *legacy_find_func_in_gadget(
157 struct usb_gadget *gadget, const char *name)
161 for (i = 0; gadget->funcs[i]; ++i)
162 if (!strcmp(name, gadget->funcs[i]->name))
163 return gadget->funcs[i];
167 static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config)
169 struct usb_configuration *config;
171 config = zalloc(sizeof(*config));
175 config->strs = calloc(1, sizeof(*config->strs));
179 config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs));
184 * We cannot read correct values
185 * so assume that they are always default
187 config->attrs.bmAttributs = LEGACY_BMATTRIBUTES;
188 config->attrs.MaxPower = LEGACY_MAX_POWER;
201 static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname,
202 struct usb_function **_func)
204 struct usb_function *func;
207 ret = legacy_find_func(fname);
211 ret = _available_funcs[ret]->clone(_available_funcs[ret], &func);
219 static int legacy_read_config(struct usb_gadget *gadget,
221 struct usb_configuration **_config)
223 struct usb_configuration *config;
224 char buf[MAX_GADGET_STR_LEN];
227 char *sep = LEGACY_FUNC_SEP;
233 ret = sys_get_str(cpath, buf, sizeof(buf));
238 if (buf[0] == '\0' || buf[0] == '\n')
241 /* count number of functions in this config */
243 for (i = 0; buf[i] != '\0'; ++i) {
244 if (buf[i] == sep[0])
246 if (buf[i] == '\n') /* buf ends with it */
250 ret = legacy_alloc_config(f_cnt, &config);
254 for (g_f_idx = 0; gadget->funcs[g_f_idx]; ++g_f_idx);
257 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
258 struct usb_function *func;
260 func = legacy_find_func_in_gadget(gadget, fname);
262 /* new function not added yet to gadget */
263 ret = legacy_alloc_new_func(gadget, fname, &func);
267 gadget->funcs[g_f_idx++] = func;
270 config->funcs[f_idx++] = func;
282 static int legacy_get_current_gadget(struct usb_client *usb,
283 struct usb_gadget **_gadget)
285 struct usb_gadget *gadget;
286 struct usb_gadget_strings *strs;
287 struct usb_configuration **configs;
288 struct usb_function **funcs;
292 gadget = zalloc(sizeof(*gadget));
296 strs = calloc(2, sizeof(*strs));
300 strs[0].lang_code = 0x409;
304 ret = legacy_read_gadget_attrs_strs(gadget);
308 /* There will be no more functions than bits in int */
309 funcs = calloc(MAX_FUNCS, sizeof(*funcs));
311 goto free_strs_with_content;
313 gadget->funcs = funcs;
315 /* slp-gadget use max 2 confiuration and NULL termination */
316 configs = calloc(3, sizeof(*configs));
320 gadget->configs = configs;
322 ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0);
326 ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1);
334 free(configs[0]->funcs);
335 free(configs[0]->strs);
339 for (i = 0; gadget->funcs[i]; ++i)
340 gadget->funcs[i]->free_func(gadget->funcs[i]);
343 free_strs_with_content:
344 free(gadget->strs[0].manufacturer);
345 free(gadget->strs[0].product);
346 free(gadget->strs[0].serial);
355 static bool legacy_is_function_supported(struct usb_client *usb,
356 struct usb_function *func)
362 * Instead of only checking whether we know this function
363 * we should also parse sysfs to check if it is build into
366 ret = legacy_find_func(func->name);
371 static bool legacy_is_gadget_supported(struct usb_client *usb,
372 struct usb_gadget *gadget)
376 if (!gadget || !gadget->configs || !gadget->funcs)
381 * Here is a good place to ensure that serial is immutable
384 /* only strings in US_en are allowed */
385 if (gadget->strs[0].lang_code != 0x409 ||
386 gadget->strs[1].lang_code)
390 for (j = 0; gadget->configs[j]; ++j) {
391 struct usb_configuration *config = gadget->configs[j];
393 if (config->strs && config->strs[0].lang_code)
399 for (i = 0; config->funcs[i]; ++i)
400 if (!legacy_is_function_supported(usb, config->funcs[i]))
410 /* TODO. Maybe move this to sys ? */
411 static int legacy_set_int_hex(char *path, int val)
413 char buf[MAX_GADGET_STR_LEN];
419 snprintf(buf, sizeof(buf), "%x", val);
420 r = sys_set_str(path, buf);
427 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
431 ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
435 ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
439 ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
443 ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
447 ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
451 ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
456 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
462 * Here is a good place to ensure that serial is immutable
465 if (strs->manufacturer) {
466 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH,
473 ret = sys_set_str(LEGACY_IPRODUCT_PATH,
482 static int legacy_set_gadget_config(char *cpath,
483 struct usb_configuration *config)
485 char buf[MAX_GADGET_STR_LEN];
486 int left = sizeof(buf);
497 for (i = 0; config->funcs[i]; ++i) {
498 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
499 config->funcs[i]->name);
507 /* eliminate last separator */
511 return sys_set_str(cpath, buf);
514 static int legacy_reconfigure_gadget(struct usb_client *usb,
515 struct usb_gadget *gadget)
519 if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget))
522 ret = legacy_set_gadget_attrs(&gadget->attrs);
527 ret = legacy_set_gadget_strs(gadget->strs + 0);
532 ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
536 ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
541 static int legacy_enable(struct usb_client *usb)
545 struct usb_gadget *gadget;
546 struct usb_function_with_service *fws;
548 ret = sys_set_str(LEGACY_ENABLE_PATH,
553 ret = legacy_get_current_gadget(usb, &gadget);
557 for (i = 0; gadget->funcs[i]; ++i) {
558 if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
561 fws = container_of(gadget->funcs[i],
562 struct usb_function_with_service, func);
563 systemd_start_unit_wait_started(fws->service, ".service", -1);
566 legacy_free_gadget(gadget);
570 sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
574 static int legacy_disable(struct usb_client *usb)
578 struct usb_gadget *gadget;
579 struct usb_function_with_service *fws;
581 ret = legacy_get_current_gadget(usb, &gadget);
585 for (i = 0; gadget->funcs[i]; ++i) {
586 if (gadget->funcs[i]->function_group == USB_FUNCTION_GROUP_SIMPLE)
589 fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
590 systemd_stop_unit_wait_stopped(fws->service, ".service", -1);
593 ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
595 legacy_free_gadget(gadget);
599 static void legacy_free_config(struct usb_configuration *config)
607 for (i = 0; config->strs[i].lang_code; ++i)
608 free(config->strs[i].config_str);
614 * Each function will be free later,
615 * for now we cleanup only pointers.
623 static void legacy_free_gadget(struct usb_gadget *gadget)
631 for (i = 0; gadget->strs[i].lang_code; ++i) {
632 free(gadget->strs[i].manufacturer);
633 free(gadget->strs[i].product);
634 free(gadget->strs[i].serial);
639 if (gadget->configs) {
640 for (i = 0; gadget->configs[i]; ++i)
641 legacy_free_config(gadget->configs[i]);
643 free(gadget->configs);
647 for (i = 0; gadget->funcs[i]; ++i)
648 gadget->funcs[i]->free_func(gadget->funcs[i]);
657 int hw_legacy_gadget_open(struct hw_info *info,
658 const char *id, struct hw_common **common)
660 struct usb_client *legacy;
662 if (!info || !common)
665 /* check if slp usb gadget exists */
666 if (access("/sys/class/usb_mode/usb0/enable", F_OK))
669 legacy = zalloc(sizeof(*legacy));
673 legacy->common.info = info;
674 legacy->get_current_gadget = legacy_get_current_gadget;
675 legacy->reconfigure_gadget = legacy_reconfigure_gadget;
676 legacy->is_gadget_supported = legacy_is_gadget_supported;
677 legacy->is_function_supported = legacy_is_function_supported;
678 legacy->enable = legacy_enable;
679 legacy->disable = legacy_disable;
680 legacy->free_gadget = legacy_free_gadget;
682 *common = &legacy->common;
687 int hw_legacy_gadget_close(struct hw_common *common)
689 struct usb_client *legacy;
694 legacy = container_of(common, struct usb_client,