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);
69 static int alloc_default_config(struct usb_configuration **_config)
71 struct usb_configuration *config;
73 config = calloc(1, sizeof(*config));
77 config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
78 config->attrs.MaxPower = DEFAULT_MAX_POWER;
80 /* TODO. Here is where to set the string used in config of configfs */
87 static int get_device_serial(char **out)
90 struct hw_common *common;
91 struct hw_board *board;
94 if (hw_get_info(BOARD_HARDWARE_DEVICE_ID, (const struct hw_info **)&info))
97 ret = info->open(info, NULL, &common);
101 board = container_of(common, struct hw_board, common);
102 return board->get_device_serial(out);
105 static int alloc_default_gadget(struct usb_gadget **_gadget)
107 struct usb_gadget *gadget;
108 struct usb_configuration **configs;
110 gadget = calloc(1, sizeof(*gadget));
114 gadget->attrs.idVendor = DEFAULT_VID;
115 gadget->attrs.idProduct = DEFAULT_PID;
116 gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
118 gadget->strs.lang_code = DEFAULT_LANG;
119 gadget->strs.manufacturer = strdup(DEFAULT_MANUFACTURER);
120 gadget->strs.product = strdup(DEFAULT_PRODUCT);
121 if (get_device_serial(&gadget->strs.serial) < 0)
122 gadget->strs.serial = strdup(DEFAULT_SERIAL);
124 if (!gadget->strs.manufacturer || !gadget->strs.product || !gadget->strs.serial)
127 /* slp-gadget use max 2 confiuration and NULL termination */
128 configs = calloc(3, sizeof(*configs));
132 gadget->configs = configs;
138 free(gadget->strs.manufacturer);
139 free(gadget->strs.product);
140 free(gadget->strs.serial);
146 static int id_to_gadget(struct usb_gadget_id *gadget_id, struct usb_gadget **_gadget)
151 struct usb_gadget *gadget;
152 int functions[2][sizeof(gadget_id->function_mask)*8]; /* zero terminates */
154 if (!gadget_id || !_gadget)
157 ret = alloc_default_gadget(&gadget);
162 * Currently all gadgets use inly single configuration but
163 * slp-gadget is capable to handle two of them
165 * Order of interfaces in configuration is significant
166 * so in this switch we sort our functions in a correct order
168 switch (gadget_id->function_mask) {
170 case USB_FUNCTION_MTP | USB_FUNCTION_ACM:
172 functions[0][0] = USB_FUNCTION_MTP;
173 functions[0][1] = USB_FUNCTION_ACM;
175 gadget->attrs.idProduct = 0x6860;
178 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
180 functions[0][0] = USB_FUNCTION_MTP;
181 functions[0][1] = USB_FUNCTION_ACM;
182 functions[0][2] = USB_FUNCTION_SDB;
184 gadget->attrs.idProduct = 0x6860;
188 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
190 functions[0][0] = USB_FUNCTION_MTP;
191 functions[0][1] = USB_FUNCTION_ACM;
192 functions[0][2] = USB_FUNCTION_SDB;
193 functions[0][3] = USB_FUNCTION_DIAG;
195 gadget->attrs.idProduct = 0x6860;
199 case USB_FUNCTION_RNDIS:
201 functions[0][0] = USB_FUNCTION_RNDIS;
203 gadget->attrs.idProduct = 0x6863;
206 case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
208 functions[0][0] = USB_FUNCTION_RNDIS;
209 functions[0][1] = USB_FUNCTION_DIAG;
211 gadget->attrs.idProduct = 0x6864;
214 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_RNDIS:
216 functions[0][0] = USB_FUNCTION_RNDIS;
217 functions[0][1] = USB_FUNCTION_ACM;
218 functions[0][2] = USB_FUNCTION_SDB;
220 gadget->attrs.idProduct = 0x6864;
224 case USB_FUNCTION_DIAG | USB_FUNCTION_RMNET:
226 functions[0][0] = USB_FUNCTION_DIAG;
227 functions[0][1] = USB_FUNCTION_RMNET;
229 gadget->attrs.idProduct = 0x685d;
233 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
235 functions[0][0] = USB_FUNCTION_ACM;
236 functions[0][1] = USB_FUNCTION_SDB;
237 functions[0][2] = USB_FUNCTION_DM;
239 gadget->attrs.idProduct = 0x6860;
247 for (j = 0; j < n_configs; ++j) {
248 int n_funcs_in_config;
249 struct usb_configuration *config;
251 for (i = 0; functions[j][i]; ++i);
252 n_funcs_in_config = i;
254 ret = alloc_default_config(&config);
258 gadget->configs[j] = config;
259 config->funcs = calloc(n_funcs_in_config + 1, sizeof(void *));
263 for (i = 0; functions[j][i]; ++i) {
264 config->funcs[i] = find_usb_function_by_id(functions[j][i]);
265 if (!config->funcs[i])
276 cleanup_gadget(gadget);
281 void rndis_handler(int enable)
284 (void)systemd_start_unit_wait_started("rndis.service", NULL, -1);
286 (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1);
289 #define DEFINE_USB_FUNCTION(_id, _name, _is_functionfs, _service, _handler) \
290 static struct usb_function _##_name##_function = { \
293 .instance = "default", \
294 .is_functionfs = _is_functionfs, \
295 .service = _service, \
296 .handler = _handler, \
299 DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, 1, "mtp-responder", NULL);
300 DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, 0, "data-router", NULL);
301 DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, 1, "sdbd", NULL);
302 DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, 0, "sshd", rndis_handler);
303 DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, 0, NULL, NULL);
304 DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, 0, NULL, NULL);
305 DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, 0, NULL, NULL);
306 DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, 0, NULL, NULL);
308 #undef DEFINE_USB_FUNCTION
310 /* Caution: index order of arrary is important, because simple_translator_open() uses it. */
311 static struct usb_function *_available_funcs[] = {
312 [USB_FUNCTION_IDX_MTP] = &_mtp_function,
313 [USB_FUNCTION_IDX_ACM] = &_acm_function,
314 [USB_FUNCTION_IDX_SDB] = &_sdb_function,
315 [USB_FUNCTION_IDX_RNDIS] = &_rndis_function,
316 [USB_FUNCTION_IDX_DIAG] = &_diag_function,
317 [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function,
318 [USB_FUNCTION_IDX_DM] = &_dm_function,
319 [USB_FUNCTION_IDX_RMNET] = &_rmnet_function,
320 [USB_FUNCTION_IDX_MAX] = NULL /* An indicator to end the array */
323 struct usb_function *find_usb_function_by_id(int id)
327 for (i = 0; _available_funcs[i]; i++)
328 if (_available_funcs[i]->id == id)
329 return _available_funcs[i];
334 struct usb_function *find_usb_function_by_name(const char *name)
338 if(!name || !name[0])
341 for (i = 0; _available_funcs[i]; i++)
342 if (!strcmp(name, _available_funcs[i]->name))
343 return _available_funcs[i];
348 struct usb_function *find_usb_function_by_name_instance(const char *name, const char *instance)
352 if(!name || !name[0] || !instance || !instance[0])
355 for (i = 0; _available_funcs[i]; ++i)
356 if (!strcmp(name, _available_funcs[i]->name) && !strcmp(instance, _available_funcs[i]->instance))
357 return _available_funcs[i];
364 int simple_translator_open(struct hw_info *info,
365 const char *id, struct hw_common **common)
367 struct usb_gadget_translator *simple_translator;
369 if (!info || !common)
372 simple_translator = calloc(1, sizeof(*simple_translator));
373 if (!simple_translator)
376 simple_translator->common.info = info;
377 simple_translator->id_to_gadget = id_to_gadget;
378 simple_translator->cleanup_gadget = cleanup_gadget;
380 /* Use mtp-responder-dummy.socket when there is no mtp-responser.socket.
382 * The mtp-responder.socket is special in the configfs environment.
383 * If mtp-responder.socket is missing, gadget configuration will fail.
384 * As a result, all usb operations do not work properly.
385 * So in environments that mtp doesn't support, use dummy mtp.
387 if (access("/usr/lib/systemd/system/mtp-responder.socket", F_OK)) {
388 _available_funcs[USB_FUNCTION_IDX_MTP]->service = "mtp-responder-dummy";
391 *common = &simple_translator->common;
396 int simple_translator_close(struct hw_common *common)
398 struct usb_gadget_translator *simple_translator;
403 simple_translator = container_of(common, struct usb_gadget_translator,
406 free(simple_translator);