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>
27 #include <hw/usb_gadget.h>
30 #define EXPORT __attribute__ ((visibility("default")))
33 static struct usb_function *_available_funcs[];
35 static void simple_cleanup_config(struct usb_configuration *config)
40 free(config->strs.config_str);
48 static void cleanup_gadget(struct usb_gadget *gadget)
55 free(gadget->strs.manufacturer);
56 free(gadget->strs.product);
57 free(gadget->strs.serial);
59 if (gadget->configs) {
60 for (i = 0; gadget->configs[i]; ++i)
61 simple_cleanup_config(gadget->configs[i]);
63 free(gadget->configs);
72 static int alloc_default_config(struct usb_configuration **_config)
74 struct usb_configuration *config;
76 config = calloc(1, sizeof(*config));
80 config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
81 config->attrs.MaxPower = DEFAULT_MAX_POWER;
83 /* TODO. Here is where to set the string used in config of configfs */
90 static int get_device_serial(char **out)
93 struct hw_common *common;
94 struct hw_board *board;
97 if (hw_get_info(BOARD_HARDWARE_DEVICE_ID, (const struct hw_info **)&info))
100 ret = info->open(info, NULL, &common);
104 board = container_of(common, struct hw_board, common);
105 return board->get_device_serial(out);
108 static int alloc_default_gadget(struct usb_gadget **_gadget)
110 struct usb_gadget *gadget;
111 struct usb_configuration **configs;
113 gadget = calloc(1, sizeof(*gadget));
117 gadget->attrs.idVendor = DEFAULT_VID;
118 gadget->attrs.idProduct = DEFAULT_PID;
119 gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
121 gadget->strs.lang_code = DEFAULT_LANG;
122 gadget->strs.manufacturer = strdup(DEFAULT_MANUFACTURER);
123 gadget->strs.product = strdup(DEFAULT_PRODUCT);
124 if (get_device_serial(&gadget->strs.serial) < 0)
125 gadget->strs.serial = strdup(DEFAULT_SERIAL);
127 if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial)
130 /* slp-gadget use max 2 confiuration and NULL termination */
131 configs = calloc(3, sizeof(*configs));
135 gadget->configs = configs;
141 free(gadget->strs.manufacturer);
142 free(gadget->strs.product);
143 free(gadget->strs.serial);
149 static inline struct usb_function *find_func(struct usb_gadget *gadget,
154 for (i = 0; gadget->funcs[i] && gadget->funcs[i]->id != func_id; ++i);
156 return gadget->funcs[i];
159 static int id_to_gadget(struct usb_gadget_id *gadget_id,
160 struct usb_gadget **_gadget)
166 struct usb_gadget *gadget;
167 struct usb_function **funcs;
168 int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */
170 if (!gadget_id || !_gadget)
173 ret = alloc_default_gadget(&gadget);
178 * Currently all gadgets use inly single configuration but
179 * slp-gadget is capable to handle two of them
181 * Order of interfaces in configuration is significant
182 * so in this switch we sort our functions in a correct order
184 switch (gadget_id->function_mask) {
186 case USB_FUNCTION_MTP | USB_FUNCTION_ACM:
188 functions[0][0] = USB_FUNCTION_MTP;
189 functions[0][1] = USB_FUNCTION_ACM;
191 gadget->attrs.idProduct = 0x6860;
194 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
196 functions[0][0] = USB_FUNCTION_MTP;
197 functions[0][1] = USB_FUNCTION_ACM;
198 functions[0][2] = USB_FUNCTION_SDB;
200 gadget->attrs.idProduct = 0x6860;
204 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
206 functions[0][0] = USB_FUNCTION_MTP;
207 functions[0][1] = USB_FUNCTION_ACM;
208 functions[0][2] = USB_FUNCTION_SDB;
209 functions[0][3] = USB_FUNCTION_DIAG;
211 gadget->attrs.idProduct = 0x6860;
215 case USB_FUNCTION_RNDIS:
217 functions[0][0] = USB_FUNCTION_RNDIS;
219 gadget->attrs.idProduct = 0x6863;
222 case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
224 functions[0][0] = USB_FUNCTION_RNDIS;
225 functions[0][1] = USB_FUNCTION_DIAG;
227 gadget->attrs.idProduct = 0x6864;
230 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
232 functions[0][0] = USB_FUNCTION_RNDIS;
233 functions[0][1] = USB_FUNCTION_ACM;
234 functions[0][2] = USB_FUNCTION_SDB;
236 gadget->attrs.idProduct = 0x6864;
240 case USB_FUNCTION_DIAG | USB_FUNCTION_RMNET:
242 functions[0][0] = USB_FUNCTION_DIAG;
243 functions[0][1] = USB_FUNCTION_RMNET;
245 gadget->attrs.idProduct = 0x685d;
249 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
251 functions[0][0] = USB_FUNCTION_ACM;
252 functions[0][1] = USB_FUNCTION_SDB;
253 functions[0][2] = USB_FUNCTION_DM;
255 gadget->attrs.idProduct = 0x6860;
263 n_functions = __builtin_popcount(gadget_id->function_mask);
265 funcs = calloc(n_functions + 1, sizeof(*funcs));
271 gadget->funcs = funcs;
274 for (i = 0; _available_funcs[i]; ++i) {
275 int func_id = 1 << i;
277 if (!(gadget_id->function_mask & func_id))
280 gadget->funcs[idx] = _available_funcs[i];
284 for (j = 0; j < n_configs; ++j) {
285 struct usb_configuration *config;
286 int n_funcs_in_config;
288 for (i = 0; functions[j][i]; ++i);
289 n_funcs_in_config = i;
291 ret = alloc_default_config(&config);
295 gadget->configs[j] = config;
296 config->funcs = calloc(n_funcs_in_config + 1,
301 for (i = 0; functions[j][i]; ++i)
302 config->funcs[i] = find_func(gadget, functions[j][i]);
310 cleanup_gadget(gadget);
315 void rndis_handler(int enable)
318 (void)systemd_start_unit_wait_started("rndis.service", NULL, -1);
320 (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1);
323 #define DEFINE_USB_FUNCTION(_id, _name, _is_functionfs, _service, _handler) \
324 static struct usb_function _##_name##_function = { \
327 .instance = "default", \
328 .is_functionfs = _is_functionfs, \
329 .service = _service, \
330 .handler = _handler, \
333 DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, 1, "mtp-responder", NULL);
334 DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, 0, "data-router", NULL);
335 DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, 1, "sdbd", NULL);
336 DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, 0, "sshd", rndis_handler);
337 DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, 0, NULL, NULL);
338 DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, 0, NULL, NULL);
339 DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, 0, NULL, NULL);
340 DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, 0, NULL, NULL);
342 #undef DEFINE_USB_FUNCTION
344 /* Caution: index order of arrary is important, because id_to_gadget() uses it. */
345 static struct usb_function *_available_funcs[] = {
346 [USB_FUNCTION_IDX_MTP] = &_mtp_function,
347 [USB_FUNCTION_IDX_ACM] = &_acm_function,
348 [USB_FUNCTION_IDX_SDB] = &_sdb_function,
349 [USB_FUNCTION_IDX_RNDIS] = &_rndis_function,
350 [USB_FUNCTION_IDX_DIAG] = &_diag_function,
351 [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function,
352 [USB_FUNCTION_IDX_DM] = &_dm_function,
353 [USB_FUNCTION_IDX_RMNET] = &_rmnet_function,
354 [USB_FUNCTION_IDX_MAX] = NULL /* An indicator to end the array */
357 struct usb_function *find_usb_function_by_name(const char *name)
361 if(!name || !name[0])
364 for (i = 0; _available_funcs[i]; i++)
365 if (!strcmp(name, _available_funcs[i]->name))
366 return _available_funcs[i];
371 struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance)
375 if(!name || !name[0] || !instance || !instance[0])
378 for (i = 0; _available_funcs[i]; ++i)
379 if (!strcmp(name, _available_funcs[i]->name) && !strcmp(instance, _available_funcs[i]->instance))
380 return _available_funcs[i];
387 int simple_translator_open(struct hw_info *info,
388 const char *id, struct hw_common **common)
390 struct usb_gadget_translator *simple_translator;
392 if (!info || !common)
395 simple_translator = calloc(1, sizeof(*simple_translator));
396 if (!simple_translator)
399 simple_translator->common.info = info;
400 simple_translator->id_to_gadget = id_to_gadget;
401 simple_translator->cleanup_gadget = cleanup_gadget;
403 /* Use mtp-responder-dummy.socket when there is no mtp-responser.socket.
405 * The mtp-responder.socket is special in the configfs environment.
406 * If mtp-responder.socket is missing, gadget configuration will fail.
407 * As a result, all usb operations do not work properly.
408 * So in environments that mtp doesn't support, use dummy mtp.
410 if (access("/usr/lib/systemd/system/mtp-responder.socket", F_OK)) {
411 _available_funcs[USB_FUNCTION_IDX_MTP]->service = "mtp-responder-dummy";
414 *common = &simple_translator->common;
419 int simple_translator_close(struct hw_common *common)
421 struct usb_gadget_translator *simple_translator;
426 simple_translator = container_of(common, struct usb_gadget_translator,
429 free(simple_translator);