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)
43 for (i = 0; config->strs[i].lang_code; ++i)
44 free(config->strs[i].config_str);
55 static void simple_cleanup_gadget(struct usb_gadget *gadget)
63 for (i = 0; gadget->strs[i].lang_code; ++i) {
64 free(gadget->strs[i].manufacturer);
65 free(gadget->strs[i].product);
66 free(gadget->strs[i].serial);
71 if (gadget->configs) {
72 for (i = 0; gadget->configs[i]; ++i)
73 simple_cleanup_config(gadget->configs[i]);
75 free(gadget->configs);
84 static int alloc_default_config(struct usb_configuration **_config)
86 struct usb_configuration *config;
88 config = calloc(1, sizeof(*config));
92 config->strs = calloc(1, sizeof(*config->strs));
96 config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
97 config->attrs.MaxPower = DEFAULT_MAX_POWER;
109 static int get_device_serial(char **out)
111 struct hw_info *info;
112 struct hw_common *common;
113 struct hw_board *board;
116 if (hw_get_info(BOARD_HARDWARE_DEVICE_ID, (const struct hw_info **)&info))
119 ret = info->open(info, NULL, &common);
123 board = container_of(common, struct hw_board, common);
124 return board->get_device_serial(out);
127 static int alloc_default_gadget(struct usb_gadget **_gadget)
129 struct usb_gadget *gadget;
130 struct usb_gadget_strings *strs;
131 struct usb_configuration **configs;
133 gadget = calloc(1, sizeof(*gadget));
137 gadget->attrs.idVendor = DEFAULT_VID;
138 gadget->attrs.idProduct = DEFAULT_PID;
139 gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
141 strs = calloc(2, sizeof(*strs));
145 strs[0].lang_code = DEFAULT_LANG;
146 strs[0].manufacturer = strdup(DEFAULT_MANUFACTURER);
147 strs[0].product = strdup(DEFAULT_PRODUCT);
148 if (get_device_serial(&strs[0].serial) < 0)
149 strs[0].serial = strdup(DEFAULT_SERIAL);
151 if (!strs[0].manufacturer || !strs[0].product || !strs[0].serial)
156 /* slp-gadget use max 2 confiuration and NULL termination */
157 configs = calloc(3, sizeof(*configs));
161 gadget->configs = configs;
167 free(strs[0].manufacturer);
168 free(strs[0].product);
169 free(strs[0].serial);
177 static inline struct usb_function *find_func(struct usb_gadget *gadget,
182 for (i = 0; gadget->funcs[i] && gadget->funcs[i]->id != func_id; ++i);
184 return gadget->funcs[i];
187 static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
188 struct usb_gadget **_gadget)
194 struct usb_gadget *gadget;
195 struct usb_function **funcs;
196 int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */
198 if (!gadget_id || !_gadget)
201 ret = alloc_default_gadget(&gadget);
206 * Currently all gadgets use inly single configuration but
207 * slp-gadget is capable to handle two of them
209 * Order of interfaces in configuration is significant
210 * so in this switch we sort our functions in a correct order
212 switch (gadget_id->function_mask) {
214 case USB_FUNCTION_MTP | USB_FUNCTION_ACM:
216 functions[0][0] = USB_FUNCTION_MTP;
217 functions[0][1] = USB_FUNCTION_ACM;
219 gadget->attrs.idProduct = 0x6860;
222 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
224 functions[0][0] = USB_FUNCTION_MTP;
225 functions[0][1] = USB_FUNCTION_ACM;
226 functions[0][2] = USB_FUNCTION_SDB;
228 gadget->attrs.idProduct = 0x6860;
232 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
234 functions[0][0] = USB_FUNCTION_MTP;
235 functions[0][1] = USB_FUNCTION_ACM;
236 functions[0][2] = USB_FUNCTION_SDB;
237 functions[0][3] = USB_FUNCTION_DIAG;
239 gadget->attrs.idProduct = 0x6860;
243 case USB_FUNCTION_RNDIS:
245 functions[0][0] = USB_FUNCTION_RNDIS;
247 gadget->attrs.idProduct = 0x6863;
250 case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
252 functions[0][0] = USB_FUNCTION_RNDIS;
253 functions[0][1] = USB_FUNCTION_DIAG;
255 gadget->attrs.idProduct = 0x6864;
258 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
260 functions[0][0] = USB_FUNCTION_ACM;
261 functions[0][1] = USB_FUNCTION_SDB;
262 functions[0][2] = USB_FUNCTION_RNDIS;
264 gadget->attrs.idProduct = 0x6864;
268 case USB_FUNCTION_DIAG | USB_FUNCTION_RMNET:
270 functions[0][0] = USB_FUNCTION_DIAG;
271 functions[0][1] = USB_FUNCTION_RMNET;
273 gadget->attrs.idProduct = 0x685d;
277 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
279 functions[0][0] = USB_FUNCTION_ACM;
280 functions[0][1] = USB_FUNCTION_SDB;
281 functions[0][2] = USB_FUNCTION_DM;
283 gadget->attrs.idProduct = 0x6860;
291 n_functions = __builtin_popcount(gadget_id->function_mask);
293 funcs = calloc(n_functions + 1, sizeof(*funcs));
299 gadget->funcs = funcs;
302 for (i = 0; _available_funcs[i]; ++i) {
303 int func_id = 1 << i;
305 if (!(gadget_id->function_mask & func_id))
308 gadget->funcs[idx] = _available_funcs[i];
312 for (j = 0; j < n_configs; ++j) {
313 struct usb_configuration *config;
314 int n_funcs_in_config;
316 for (i = 0; functions[j][i]; ++i);
317 n_funcs_in_config = i;
319 ret = alloc_default_config(&config);
323 gadget->configs[j] = config;
324 config->funcs = calloc(n_funcs_in_config + 1,
329 for (i = 0; functions[j][i]; ++i)
330 config->funcs[i] = find_func(gadget, functions[j][i]);
338 simple_cleanup_gadget(gadget);
343 void rndis_handler(int enable)
346 (void)systemd_start_unit_wait_started("rndis.service", NULL, -1);
348 (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1);
351 #define DEFINE_USB_FUNCTION(_id, _name, _is_functionfs, _service, _handler) \
352 static struct usb_function _##_name##_function = { \
355 .instance = "default", \
356 .is_functionfs = _is_functionfs, \
357 .service = _service, \
358 .handler = _handler, \
361 DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, 1, "mtp-responder", NULL);
362 DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, 0, "data-router", NULL);
363 DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, 1, "sdbd", NULL);
364 DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, 0, "sshd", rndis_handler);
365 DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, 0, NULL, NULL);
366 DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, 0, NULL, NULL);
367 DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, 0, NULL, NULL);
368 DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, 0, NULL, NULL);
370 #undef DEFINE_USB_FUNCTION
372 /* Caution: index order of arrary is important, because simple_id_to_gadget() uses it. */
373 static struct usb_function *_available_funcs[] = {
374 [USB_FUNCTION_IDX_MTP] = &_mtp_function,
375 [USB_FUNCTION_IDX_ACM] = &_acm_function,
376 [USB_FUNCTION_IDX_SDB] = &_sdb_function,
377 [USB_FUNCTION_IDX_RNDIS] = &_rndis_function,
378 [USB_FUNCTION_IDX_DIAG] = &_diag_function,
379 [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function,
380 [USB_FUNCTION_IDX_DM] = &_dm_function,
381 [USB_FUNCTION_IDX_RMNET] = &_rmnet_function,
382 [USB_FUNCTION_IDX_MAX] = NULL /* An indicator to end the array */
385 struct usb_function *find_usb_function_by_name(const char *name)
389 if(!name || !name[0])
392 for (i = 0; _available_funcs[i]; i++)
393 if (!strcmp(name, _available_funcs[i]->name))
394 return _available_funcs[i];
399 struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance)
403 if(!name || !name[0] || !instance || !instance[0])
406 for (i = 0; _available_funcs[i]; ++i)
407 if (!strcmp(name, _available_funcs[i]->name) && !strcmp(instance, _available_funcs[i]->instance))
408 return _available_funcs[i];
415 int simple_translator_open(struct hw_info *info,
416 const char *id, struct hw_common **common)
418 struct usb_gadget_translator *simple_translator;
420 if (!info || !common)
423 simple_translator = calloc(1, sizeof(*simple_translator));
424 if (!simple_translator)
427 simple_translator->common.info = info;
428 simple_translator->id_to_gadget = simple_id_to_gadget;
429 simple_translator->cleanup_gadget = simple_cleanup_gadget;
431 /* Use mtp-responder-dummy.socket when there is no mtp-responser.socket.
433 * The mtp-responder.socket is special in the configfs environment.
434 * If mtp-responder.socket is missing, gadget configuration will fail.
435 * As a result, all usb operations do not work properly.
436 * So in environments that mtp doesn't support, use dummy mtp.
438 if (access("/usr/lib/systemd/system/mtp-responder.socket", F_OK)) {
439 _available_funcs[USB_FUNCTION_IDX_MTP]->service = "mtp-responder-dummy";
442 *common = &simple_translator->common;
447 int simple_translator_close(struct hw_common *common)
449 struct usb_gadget_translator *simple_translator;
454 simple_translator = container_of(common, struct usb_gadget_translator,
457 free(simple_translator);