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.
24 #include <libsyscommon/dbus-systemd.h>
26 #include <hw/shared.h>
27 #include <hw/usb_client.h>
29 #define MAX_GADGET_STR_LEN 256
31 #define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0"
33 /* Device descriptor values */
34 #define LEGACY_ID_VENDOR_PATH LEGACY_ROOTPATH"/idVendor"
35 #define LEGACY_ID_PRODUCT_PATH LEGACY_ROOTPATH"/idProduct"
36 #define LEGACY_BCD_DEVICE_PATH LEGACY_ROOTPATH"/bcdDevice"
37 #define LEGACY_CLASS_PATH LEGACY_ROOTPATH"/bDeviceClass"
38 #define LEGACY_SUBCLASS_PATH LEGACY_ROOTPATH"/bDeviceSubClass"
39 #define LEGACY_PROTOCOL_PATH LEGACY_ROOTPATH"/bDeviceProtocol"
42 #define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer"
43 #define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct"
45 /* Functions in each config */
46 #define LEGACY_CONFIG_1_PATH LEGACY_ROOTPATH"/funcs_fconf"
47 #define LEGACY_CONFIG_2_PATH LEGACY_ROOTPATH"/funcs_sconf"
49 /* should be single char */
50 #define LEGACY_FUNC_SEP ","
53 #define LEGACY_ENABLE_PATH LEGACY_ROOTPATH"/enable"
54 #define LEGACY_ENABLE "1"
55 #define LEGACY_DISABLE "0"
58 #define EXPORT __attribute__ ((visibility("default")))
61 static bool legacy_is_function_supported(struct usb_client *usb,
62 const struct usb_function *func)
66 * Instead of only checking whether we know this function
67 * we should also parse sysfs to check if it is build into
70 if (find_usb_function_by_name(func->name))
76 static bool legacy_is_gadget_supported(struct usb_client *usb,
77 struct usb_gadget *gadget)
81 if (!gadget || !gadget->configs || !gadget->funcs)
86 * Here is a good place to ensure that serial is immutable
89 /* only strings in US_en are allowed */
90 if (gadget->strs[0].lang_code != 0x409 ||
91 gadget->strs[1].lang_code)
95 for (j = 0; gadget->configs[j]; ++j) {
96 struct usb_configuration *config = gadget->configs[j];
98 if (config->strs && config->strs[0].lang_code)
104 for (i = 0; config->funcs[i]; ++i)
105 if (!legacy_is_function_supported(usb, config->funcs[i]))
115 /* TODO. Maybe move this to sys ? */
116 static int legacy_set_int_hex(char *path, int val)
118 char buf[MAX_GADGET_STR_LEN];
124 snprintf(buf, sizeof(buf), "%x", val);
125 r = sys_set_str(path, buf);
132 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
136 ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
140 ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
144 ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
148 ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
152 ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
156 ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
161 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
167 * Here is a good place to ensure that serial is immutable
170 if (strs->manufacturer) {
171 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH, strs->manufacturer);
177 ret = sys_set_str(LEGACY_IPRODUCT_PATH, strs->product);
185 static int legacy_set_gadget_config(char *cpath,
186 struct usb_configuration *config)
188 char buf[MAX_GADGET_STR_LEN];
189 int left = sizeof(buf);
200 for (i = 0; config->funcs[i]; ++i) {
201 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
202 config->funcs[i]->name);
210 /* eliminate last separator */
214 return sys_set_str(cpath, buf);
217 static int legacy_reconfigure_gadget(struct usb_client *usb,
218 struct usb_gadget *gadget)
222 if (!usb || !gadget || !legacy_is_gadget_supported(usb, gadget))
225 ret = legacy_set_gadget_attrs(&gadget->attrs);
230 ret = legacy_set_gadget_strs(gadget->strs + 0);
235 ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
239 ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
244 static void legacy_start_stop_service_and_handler(bool start)
252 char *sep = LEGACY_FUNC_SEP;
253 char buf[MAX_GADGET_STR_LEN];
254 const struct usb_function *func;
255 const struct usb_function *funcs[USB_FUNCTION_IDX_MAX];
257 /* SLP gadget uses two USB configuration.
258 * (/sys/class/usb_mode/usb0/funcs_fconf and /sys/class/usb_mode/usb0/funcs_sconf)
260 * One usb function can be included in two configurations simultaneously.
261 * In this situation, a handler associated with function can be called twice for a usb function.
262 * To prevent duplicate calls,
263 * Collect all functions and remove duplicates and process them.
266 /* First configuration */
267 ret = sys_get_str(LEGACY_CONFIG_1_PATH, buf, sizeof(buf));
269 goto second_configuration;
271 /* Caution: buf ends with '\n' */
272 ptr = strchr(buf, '\n');
277 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
278 func = find_usb_function_by_name(fname);
282 for (i = 0; i < n_func; i++)
283 if (funcs[i] == func)
286 if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */
289 funcs[n_func] = func;
293 /* Second configuration */
294 second_configuration:
295 ret = sys_get_str(LEGACY_CONFIG_2_PATH, buf, sizeof(buf));
299 /* Caution: buf ends with '\n' */
300 ptr = strchr(buf, '\n');
305 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
306 func = find_usb_function_by_name(fname);
310 for (i = 0; i < n_func; i++)
311 if (funcs[i] == func)
314 if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */
317 funcs[n_func] = func;
321 for (i = 0; i < n_func; i++) {
323 if (funcs[i]->handler)
324 funcs[i]->handler(1);
326 if (funcs[i]->service)
327 (void)systemd_start_unit_wait_started(funcs[i]->service, ".service", -1);
329 if (funcs[i]->service)
330 (void)systemd_stop_unit_wait_stopped(funcs[i]->service, ".service", -1);
332 if (funcs[i]->handler)
333 funcs[i]->handler(0);
338 static int legacy_enable(struct usb_client *usb)
342 ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE);
346 legacy_start_stop_service_and_handler(true);
351 static int legacy_disable(struct usb_client *usb)
354 legacy_start_stop_service_and_handler(false);
356 return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
360 int hw_legacy_gadget_open(struct hw_info *info,
361 const char *id, struct hw_common **common)
363 struct usb_client *legacy;
365 if (!info || !common)
368 /* check if slp usb gadget exists */
369 if (access("/sys/class/usb_mode/usb0/enable", F_OK))
372 legacy = calloc(1, sizeof(*legacy));
376 legacy->common.info = info;
378 legacy->reconfigure_gadget = legacy_reconfigure_gadget;
379 legacy->enable = legacy_enable;
380 legacy->disable = legacy_disable;
382 *common = &legacy->common;
387 int hw_legacy_gadget_close(struct hw_common *common)
389 struct usb_client *legacy;
394 legacy = container_of(common, struct usb_client,