4 * Copyright (c) 2016 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>
21 #include "../shared.h"
27 #include <systemd/sd-bus.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)
66 #define SYSTEMD_DBUS_SERVICE "org.freedesktop.systemd1"
67 #define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1"
68 #define SYSTEMD_DBUS_MANAGER_IFACE "org.freedesktop.systemd1.Manager"
70 #define SYSTEMD_SERVICE_SUFFIX ".service"
71 #define MAX_SERVICE_NAME 1024
73 static int systemd_unit_interface(const char *method, const char *unit)
78 r = sd_bus_open_system(&bus);
82 r = sd_bus_call_method(bus,
85 SYSTEMD_DBUS_MANAGER_IFACE,
97 static int systemd_start_service(const char *service_name)
99 char unit[MAX_SERVICE_NAME];
102 ret = snprintf(unit, sizeof(unit), "%s" SYSTEMD_SERVICE_SUFFIX,
104 if (ret < 0 || ret >= sizeof(unit))
105 return -ENAMETOOLONG;
107 return systemd_unit_interface("StartUnit", unit);
110 static int systemd_stop_service(const char *service_name)
112 char unit[MAX_SERVICE_NAME];
115 ret = snprintf(unit, sizeof(unit), "%s" SYSTEMD_SERVICE_SUFFIX,
117 if (ret < 0 || ret >= sizeof(unit))
118 return -ENAMETOOLONG;
120 return systemd_unit_interface("StopUnit", unit);
123 static int get_int_from_file(char *path, int *_val, int base)
125 char buf[INT_BUF_SIZE];
130 ret = sys_get_str(path, buf, sizeof(buf));
134 val = strtol(buf, &endptr, base);
135 if (val == LONG_MIN || val == LONG_MAX ||
136 buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n')
144 static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget)
148 /* We assume that values received from kernel will be valid */
149 #define GET_VALUE_FROM_SYSFS(path, field, type, base) \
151 ret = get_int_from_file(path, &val, base); \
155 gadget->attrs.field = (type)val; \
158 GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t, 0);
159 GET_VALUE_FROM_SYSFS(LEGACY_SUBCLASS_PATH, bDeviceSubClass, uint8_t, 0);
160 GET_VALUE_FROM_SYSFS(LEGACY_PROTOCOL_PATH, bDeviceProtocol, uint8_t, 0);
161 GET_VALUE_FROM_SYSFS(LEGACY_ID_VENDOR_PATH, idVendor, uint16_t, 16);
162 GET_VALUE_FROM_SYSFS(LEGACY_ID_PRODUCT_PATH, idProduct, uint16_t, 16);
163 GET_VALUE_FROM_SYSFS(LEGACY_BCD_DEVICE_PATH, bcdDevice, uint16_t, 0);
164 #undef GET_VALUE_FROM_SYSFS
166 #define GET_STRING_FROM_SYSFS(path, field) \
168 char buf[MAX_GADGET_STR_LEN]; \
170 ret = sys_get_str(path, buf, sizeof(buf)); \
174 gadget->strs[0].field = strdup(buf); \
175 if (!gadget->strs[0].field) { \
181 GET_STRING_FROM_SYSFS(LEGACY_IMANUFACTURER_PATH, manufacturer);
182 GET_STRING_FROM_SYSFS(LEGACY_IPRODUCT_PATH, product);
183 GET_STRING_FROM_SYSFS(LEGACY_ISERIAL_PATH, serial);
184 #undef GET_STRING_FROM_SYSFS
189 free(gadget->strs[0].product);
191 free(gadget->strs[0].manufacturer);
196 static int legacy_find_func(const char *name)
200 for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
201 if (!strcmp(name, _available_funcs[i]->name))
207 static struct usb_function *legacy_find_func_in_gadget(
208 struct usb_gadget *gadget, const char *name)
212 for (i = 0; gadget->funcs[i]; ++i)
213 if (!strcmp(name, gadget->funcs[i]->name))
214 return gadget->funcs[i];
218 static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config)
220 struct usb_configuration *config;
222 config = zalloc(sizeof(*config));
226 config->strs = calloc(1, sizeof(*config->strs));
230 config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs));
235 * We cannot read correct values
236 * so assume that they are always default
238 config->attrs.bmAttributs = LEGACY_BMATTRIBUTES;
239 config->attrs.MaxPower = LEGACY_MAX_POWER;
252 static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname,
253 struct usb_function **_func)
255 struct usb_function *func;
258 ret = legacy_find_func(fname);
262 ret = _available_funcs[ret]->clone(_available_funcs[ret], &func);
270 static int legacy_read_config(struct usb_gadget *gadget,
272 struct usb_configuration **_config)
274 struct usb_configuration *config;
275 char buf[MAX_GADGET_STR_LEN];
278 char *sep = LEGACY_FUNC_SEP;
283 ret = sys_get_str(cpath, buf, sizeof(buf));
288 if (buf[0] == '\0' || buf[0] == '\n')
291 /* count number of functions in this config */
293 for (i = 0; buf[i] != '\0'; ++i) {
294 if (buf[i] == sep[0])
296 if (buf[i] == '\n') /* buf ends with it */
300 ret = legacy_alloc_config(f_cnt, &config);
305 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
306 struct usb_function *func;
308 func = legacy_find_func_in_gadget(gadget, fname);
310 /* new function not added yet to gadget */
311 ret = legacy_alloc_new_func(gadget, fname, &func);
316 config->funcs[f_idx++] = func;
328 static int legacy_get_current_gadget(struct usb_client *usb,
329 struct usb_gadget **_gadget)
331 struct usb_gadget *gadget;
332 struct usb_gadget_strings *strs;
333 struct usb_configuration **configs;
334 struct usb_function **funcs;
338 gadget = zalloc(sizeof(*gadget));
342 strs = calloc(2, sizeof(*strs));
346 strs[0].lang_code = 0x409;
350 ret = legacy_read_gadget_attrs_strs(gadget);
354 /* There will be no more functions than bits in int */
355 funcs = calloc(MAX_FUNCS, sizeof(*funcs));
357 goto free_strs_with_content;
359 gadget->funcs = funcs;
361 /* slp-gadget use max 2 confiuration and NULL termination */
362 configs = calloc(3, sizeof(*configs));
366 gadget->configs = configs;
368 ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0);
372 ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1);
380 free(configs[0]->funcs);
381 free(configs[0]->strs);
385 for (i = 0; gadget->funcs[i]; ++i)
386 gadget->funcs[i]->free_func(gadget->funcs[i]);
389 free_strs_with_content:
390 free(gadget->strs[0].manufacturer);
391 free(gadget->strs[0].product);
392 free(gadget->strs[0].serial);
401 static bool legacy_is_function_supported(struct usb_client *usb,
402 struct usb_function *func)
408 * Instead of only checking whether we know this function
409 * we should also parse sysfs to check if it is build into
412 ret = legacy_find_func(func->name);
417 static bool legacy_is_gadget_supported(struct usb_client *usb,
418 struct usb_gadget *gadget)
422 if (!gadget || !gadget->configs || !gadget->funcs)
427 * Here is a good place to ensure that serial is immutable
430 /* only strings in US_en are allowed */
431 if (gadget->strs[0].lang_code != 0x409 ||
432 gadget->strs[1].lang_code)
436 for (j = 0; gadget->configs[j]; ++j) {
437 struct usb_configuration *config = gadget->configs[j];
439 if (config->strs && config->strs[0].lang_code)
445 for (i = 0; config->funcs[i]; ++i)
446 if (!legacy_is_function_supported(usb, config->funcs[i]))
456 /* TODO. Maybe move this to sys ? */
457 static int legacy_set_int_hex(char *path, int val)
459 char buf[MAX_GADGET_STR_LEN];
465 snprintf(buf, sizeof(buf), "%x", val);
466 r = sys_set_str(path, buf);
473 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
477 ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
481 ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
485 ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
489 ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
493 ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
497 ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
502 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
508 * Here is a good place to ensure that serial is immutable
511 if (strs->manufacturer) {
512 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH,
519 ret = sys_set_str(LEGACY_IPRODUCT_PATH,
528 static int legacy_set_gadget_config(char *cpath,
529 struct usb_configuration *config)
531 char buf[MAX_GADGET_STR_LEN];
532 int left = sizeof(buf);
543 for (i = 0; config->funcs[i]; ++i) {
544 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
545 config->funcs[i]->name);
553 /* eliminate last separator */
557 return sys_set_str(cpath, buf);
560 static int legacy_reconfigure_gadget(struct usb_client *usb,
561 struct usb_gadget *gadget)
565 if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget))
568 ret = legacy_set_gadget_attrs(&gadget->attrs);
573 ret = legacy_set_gadget_strs(gadget->strs + 0);
578 ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
582 ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
587 static int legacy_enable(struct usb_client *usb)
591 struct usb_gadget *gadget;
592 struct usb_function_with_service *fws;
594 ret = sys_set_str(LEGACY_ENABLE_PATH,
599 ret = legacy_get_current_gadget(usb, &gadget);
603 for (i = 0; gadget->funcs[i]; ++i) {
604 if (gadget->funcs[i]->function_group !=
605 USB_FUNCTION_GROUP_WITH_SERVICE)
608 fws = container_of(gadget->funcs[i],
609 struct usb_function_with_service, func);
610 ret = systemd_start_service(fws->service);
618 if (gadget->funcs[i]->function_group !=
619 USB_FUNCTION_GROUP_WITH_SERVICE)
622 fws = container_of(gadget->funcs[i],
623 struct usb_function_with_service, func);
624 systemd_stop_service(fws->service);
628 sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
632 static int legacy_disable(struct usb_client *usb)
636 struct usb_gadget *gadget;
637 struct usb_function_with_service *fws;
639 ret = legacy_get_current_gadget(usb, &gadget);
643 for (i = 0; gadget->funcs[i]; ++i) {
644 if (gadget->funcs[i]->function_group != USB_FUNCTION_GROUP_WITH_SERVICE)
647 fws = container_of(gadget->funcs[i], struct usb_function_with_service, func);
648 ret = systemd_stop_service(fws->service);
653 return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
656 static void legacy_free_config(struct usb_configuration *config)
664 for (i = 0; config->strs[i].lang_code; ++i)
665 free(config->strs[i].config_str);
671 * Each function will be free later,
672 * for now we cleanup only pointers.
680 static void legacy_free_gadget(struct usb_gadget *gadget)
688 for (i = 0; gadget->strs[i].lang_code; ++i) {
689 free(gadget->strs[i].manufacturer);
690 free(gadget->strs[i].product);
691 free(gadget->strs[i].serial);
696 if (gadget->configs) {
697 for (i = 0; gadget->configs[i]; ++i)
698 legacy_free_config(gadget->configs[i]);
700 free(gadget->configs);
704 for (i = 0; gadget->funcs[i]; ++i)
705 gadget->funcs[i]->free_func(gadget->funcs[i]);
711 static int legacy_gadget_open(struct hw_info *info,
712 const char *id, struct hw_common **common)
714 struct usb_client *legacy;
716 if (!info || !common)
719 /* check if slp usb gadget exists */
720 if (access("/sys/class/usb_mode/usb0/enable", F_OK))
723 legacy = zalloc(sizeof(*legacy));
727 legacy->common.info = info;
728 legacy->get_current_gadget = legacy_get_current_gadget;
729 legacy->reconfigure_gadget = legacy_reconfigure_gadget;
730 legacy->is_gadget_supported = legacy_is_gadget_supported;
731 legacy->is_function_supported = legacy_is_function_supported;
732 legacy->enable = legacy_enable;
733 legacy->disable = legacy_disable;
734 legacy->free_gadget = legacy_free_gadget;
736 *common = &legacy->common;
740 static int legacy_gadget_close(struct hw_common *common)
742 struct usb_client *legacy;
747 legacy = container_of(common, struct usb_client,
754 HARDWARE_MODULE_STRUCTURE = {
755 .magic = HARDWARE_INFO_TAG,
756 .hal_version = HARDWARE_INFO_VERSION,
757 .device_version = USB_CLIENT_HARDWARE_DEVICE_VERSION,
758 .id = USB_CLIENT_HARDWARE_DEVICE_ID,
759 .name = "legacy-gadget",
760 .open = legacy_gadget_open,
761 .close = legacy_gadget_close,