2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include <linux/limits.h>
23 #include <libsyscommon/dbus-systemd.h>
24 #include <hal/device/hal-usb_gadget-interface.h>
26 #include "usb_gadget.h"
28 #define MAX_GADGET_STR_LEN 256
30 #define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0"
32 /* Device descriptor values */
33 #define LEGACY_ID_VENDOR_PATH LEGACY_ROOTPATH"/idVendor"
34 #define LEGACY_ID_PRODUCT_PATH LEGACY_ROOTPATH"/idProduct"
35 #define LEGACY_BCD_DEVICE_PATH LEGACY_ROOTPATH"/bcdDevice"
36 #define LEGACY_CLASS_PATH LEGACY_ROOTPATH"/bDeviceClass"
37 #define LEGACY_SUBCLASS_PATH LEGACY_ROOTPATH"/bDeviceSubClass"
38 #define LEGACY_PROTOCOL_PATH LEGACY_ROOTPATH"/bDeviceProtocol"
41 #define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer"
42 #define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct"
44 /* Functions in each config */
45 #define LEGACY_CONFIG_1_PATH LEGACY_ROOTPATH"/funcs_fconf"
46 #define LEGACY_CONFIG_2_PATH LEGACY_ROOTPATH"/funcs_sconf"
48 /* should be single char */
49 #define LEGACY_FUNC_SEP ","
52 #define LEGACY_ENABLE_PATH LEGACY_ROOTPATH"/enable"
53 #define LEGACY_ENABLE "1"
54 #define LEGACY_DISABLE "0"
57 #define EXPORT __attribute__ ((visibility("default")))
60 // TODO move to common code
64 #include <sys/types.h>
68 #define SHARED_H_BUF_MAX 255
70 static inline int sys_read_buf(char *file, char *buf, int len)
74 if (!file || !buf || len < 0)
77 fd = open(file, O_RDONLY);
81 r = read(fd, buf, len);
83 if ((r >= 0) && (r < len))
91 static inline int sys_write_buf(char *file, char *buf)
98 fd = open(file, O_WRONLY);
102 r = write(fd, buf, strlen(buf));
110 static inline int sys_get_str(char *fname, char *str, int len)
114 if (!fname || !str || len < 0)
117 r = sys_read_buf(fname, str, len);
124 static inline int sys_set_str(char *fname, char *val)
131 r = sys_write_buf(fname, val);
138 static inline int sys_get_int(char *fname, int *val)
140 char buf[SHARED_H_BUF_MAX];
146 r = sys_read_buf(fname, buf, sizeof(buf));
154 static inline int sys_set_int(char *fname, int val)
156 char buf[SHARED_H_BUF_MAX];
162 snprintf(buf, sizeof(buf), "%d", val);
163 r = sys_write_buf(fname, buf);
171 static bool legacy_is_function_supported(struct usb_function *func)
175 snprintf (buf, sizeof(buf), "%s/f_%s", LEGACY_ROOTPATH, func->name);
176 if (access(buf, F_OK))
182 static bool legacy_is_gadget_supported(struct usb_gadget *gadget)
185 struct usb_configuration *config;
187 if (!gadget || !gadget->configs || !gadget->configs[0] || !gadget->configs[0]->funcs[0])
190 if (!gadget->attrs.idVendor || !gadget->attrs.idProduct || !gadget->attrs.bcdDevice)
193 /* only strings in US_en are allowed */
194 if (gadget->strs.lang_code != DEFAULT_LANG)
197 if (!gadget->strs.manufacturer || !gadget->strs.product)
200 for (j = 0; gadget->configs[j]; ++j) {
201 config = gadget->configs[j];
206 for (i = 0; config->funcs[i]; ++i)
207 if (!legacy_is_function_supported(config->funcs[i]))
214 /* TODO. Maybe move this to sys ? */
215 static int legacy_set_int_hex(char *path, int val)
218 char buf[MAX_GADGET_STR_LEN];
223 snprintf(buf, sizeof(buf), "%x", val);
224 r = sys_set_str(path, buf);
231 static int legacy_set_gadget_attrs(struct usb_gadget_attrs *attrs)
235 ret = sys_set_int(LEGACY_CLASS_PATH, attrs->bDeviceClass);
239 ret = sys_set_int(LEGACY_SUBCLASS_PATH, attrs->bDeviceSubClass);
243 ret = sys_set_int(LEGACY_PROTOCOL_PATH, attrs->bDeviceProtocol);
247 ret = legacy_set_int_hex(LEGACY_ID_VENDOR_PATH, attrs->idVendor);
251 ret = legacy_set_int_hex(LEGACY_ID_PRODUCT_PATH, attrs->idProduct);
255 ret = legacy_set_int_hex(LEGACY_BCD_DEVICE_PATH, attrs->bcdDevice);
262 static int legacy_set_gadget_strs(struct usb_gadget_strings *strs)
266 if (!strs->manufacturer || !strs->product)
269 ret = sys_set_str(LEGACY_IMANUFACTURER_PATH, strs->manufacturer);
273 ret = sys_set_str(LEGACY_IPRODUCT_PATH, strs->product);
277 /* The serial is written by the slp gadget kernel driver */
282 static int legacy_set_gadget_config(char *cpath,
283 struct usb_configuration *config)
285 char buf[MAX_GADGET_STR_LEN];
286 int left = sizeof(buf);
297 for (i = 0; config->funcs[i]; ++i) {
298 ret = snprintf(pos, left, "%s" LEGACY_FUNC_SEP,
299 config->funcs[i]->name);
307 /* eliminate last separator */
311 return sys_set_str(cpath, buf);
314 static int legacy_reconfigure_gadget(struct usb_gadget *gadget)
321 /* Verify the gadget and check if function is supported */
322 if (!legacy_is_gadget_supported(gadget))
325 ret = legacy_set_gadget_attrs(&gadget->attrs);
329 ret = legacy_set_gadget_strs(&gadget->strs);
333 ret = legacy_set_gadget_config(LEGACY_CONFIG_1_PATH, gadget->configs[0]);
337 ret = legacy_set_gadget_config(LEGACY_CONFIG_2_PATH, gadget->configs[1]);
344 static void legacy_start_stop_service_and_handler(bool start)
352 char *sep = LEGACY_FUNC_SEP;
353 char buf[MAX_GADGET_STR_LEN];
354 struct usb_function *func;
355 struct usb_function *funcs[USB_FUNCTION_IDX_MAX];
357 /* SLP gadget uses two USB configuration.
358 * (/sys/class/usb_mode/usb0/funcs_fconf and /sys/class/usb_mode/usb0/funcs_sconf)
360 * One usb function can be included in two configurations simultaneously.
361 * In this situation, a handler associated with function can be called twice for a usb function.
362 * To prevent duplicate calls,
363 * Collect all functions and remove duplicates and process them.
366 /* First configuration */
367 ret = sys_get_str(LEGACY_CONFIG_1_PATH, buf, sizeof(buf));
369 goto second_configuration;
371 /* Caution: buf ends with '\n' */
372 ptr = strchr(buf, '\n');
377 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
378 func = find_usb_function_by_name(fname);
382 for (i = 0; i < n_func; i++)
383 if (funcs[i] == func)
386 if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */
389 funcs[n_func] = func;
393 /* Second configuration */
394 second_configuration:
395 ret = sys_get_str(LEGACY_CONFIG_2_PATH, buf, sizeof(buf));
399 /* Caution: buf ends with '\n' */
400 ptr = strchr(buf, '\n');
405 for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) {
406 func = find_usb_function_by_name(fname);
410 for (i = 0; i < n_func; i++)
411 if (funcs[i] == func)
414 if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */
417 funcs[n_func] = func;
421 for (i = 0; i < n_func; i++) {
423 if (funcs[i]->handler)
424 funcs[i]->handler(1);
426 if (funcs[i]->service)
427 (void)systemd_start_unit_wait_started(funcs[i]->service, ".service", -1);
429 if (funcs[i]->service)
430 (void)systemd_stop_unit_wait_stopped(funcs[i]->service, ".service", -1);
432 if (funcs[i]->handler)
433 funcs[i]->handler(0);
438 static int legacy_enable(void)
442 ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE);
446 legacy_start_stop_service_and_handler(true);
451 static int legacy_disable(void)
453 legacy_start_stop_service_and_handler(false);
455 return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE);
459 int hw_legacy_gadget_open(hal_backend_usb_gadget_funcs *usb_gadget_funcs)
461 if (!usb_gadget_funcs)
464 /* check if slp usb gadget exists */
465 if (access("/sys/class/usb_mode/usb0/enable", F_OK))
468 usb_gadget_funcs->enable = legacy_enable;
469 usb_gadget_funcs->disable = legacy_disable;
470 usb_gadget_funcs->reconfigure_gadget = legacy_reconfigure_gadget;
476 int hw_legacy_gadget_close(hal_backend_usb_gadget_funcs *usb_gadget_funcs)