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.
19 #include <hw/usb_gadget.h>
27 #include <libsyscommon/dbus-systemd.h>
29 #define zalloc(amount) calloc(1, amount)
31 /* Based on slp-gadget and initial version of USB HAL by Taeyoung Kim */
32 #define DEFAULT_VID 0x04e8
33 #define DEFAULT_PID 0x6860
34 #define DEFAULT_BCD_DEVICE 0x0100
36 #define DEFAULT_LANG 0x409 /* US_en */
37 #define DEFAULT_MANUFACTURER "Samsung"
38 #define DEFAULT_PRODUCT "TIZEN"
39 #define DEFAULT_SERIAL "01234TEST"
41 #define DEFAULT_BMATTRIBUTES ((1 << 7) | (1 << 6))
42 #define DEFAULT_MAX_POWER 500
45 #define EXPORT __attribute__ ((visibility("default")))
48 static void simple_cleanup_config(struct usb_configuration *config)
56 for (i = 0; config->strs[i].lang_code; ++i)
57 free(config->strs[i].config_str);
63 * Each function will be free later,
64 * for now we cleanup only pointers.
72 static void simple_cleanup_gadget(struct usb_gadget *gadget)
80 for (i = 0; gadget->strs[i].lang_code; ++i) {
81 free(gadget->strs[i].manufacturer);
82 free(gadget->strs[i].product);
83 free(gadget->strs[i].serial);
88 if (gadget->configs) {
89 for (i = 0; gadget->configs[i]; ++i)
90 simple_cleanup_config(gadget->configs[i]);
92 free(gadget->configs);
96 for (i = 0; gadget->funcs[i]; ++i)
97 gadget->funcs[i]->free_func(gadget->funcs[i]);
105 static int alloc_default_config(struct usb_configuration **_config)
107 struct usb_configuration *config;
109 config = zalloc(sizeof(*config));
113 config->strs = calloc(1, sizeof(*config->strs));
117 config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
118 config->attrs.MaxPower = DEFAULT_MAX_POWER;
130 static int get_device_serial(char **out)
132 struct hw_info *info;
133 struct hw_common *common;
134 struct hw_board *board;
137 if (hw_get_info(BOARD_HARDWARE_DEVICE_ID, (const struct hw_info **)&info))
140 ret = info->open(info, NULL, &common);
144 board = container_of(common, struct hw_board, common);
145 return board->get_device_serial(out);
148 static int alloc_default_gadget(struct usb_gadget **_gadget)
150 struct usb_gadget *gadget;
151 struct usb_gadget_strings *strs;
152 struct usb_configuration **configs;
155 gadget = zalloc(sizeof(*gadget));
159 gadget->attrs.idVendor = DEFAULT_VID;
160 gadget->attrs.idProduct = DEFAULT_PID;
161 gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
163 strs = calloc(2, sizeof(*strs));
167 strs[0].lang_code = 0x409;
168 strs[0].manufacturer = strdup(DEFAULT_MANUFACTURER);
169 strs[0].product = strdup(DEFAULT_PRODUCT);
170 ret = get_device_serial(&strs[0].serial);
172 strs[0].serial = strdup(DEFAULT_SERIAL);
174 if (!strs[0].manufacturer || !strs[0].product || !strs[0].serial)
179 /* slp-gadget use max 2 confiuration and NULL termination */
180 configs = calloc(3, sizeof(*configs));
184 gadget->configs = configs;
190 free(strs[0].manufacturer);
191 free(strs[0].product);
192 free(strs[0].serial);
200 static inline struct usb_function *find_func(struct usb_gadget *gadget,
205 for (i = 0; gadget->funcs[i] && gadget->funcs[i]->id != func_id; ++i);
207 return gadget->funcs[i];
210 static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
211 struct usb_gadget **_gadget)
213 struct usb_gadget *gadget;
215 /* zero terminates */
216 int functions[2][sizeof(gadget_id->function_mask)*8];
218 struct usb_function **funcs;
222 if (!gadget_id || !_gadget)
225 ret = alloc_default_gadget(&gadget);
230 * Currently all gadgets use inly single configuration but
231 * slp-gadget is capable to handle two of them
233 * Order of interfaces in configuration is significant
234 * so in this switch we sort our functions in a correct order
236 switch (gadget_id->function_mask) {
237 case USB_FUNCTION_SDB:
239 functions[0][0] = USB_FUNCTION_SDB;
241 gadget->attrs.idProduct = 0x685d;
244 case USB_FUNCTION_MTP:
246 functions[0][0] = USB_FUNCTION_MTP;
248 gadget->attrs.idProduct = 0x6860;
251 case USB_FUNCTION_RNDIS:
253 functions[0][0] = USB_FUNCTION_RNDIS;
255 gadget->attrs.idProduct = 0x6863;
258 case USB_FUNCTION_ACM | USB_FUNCTION_SDB:
260 functions[0][0] = USB_FUNCTION_ACM;
261 functions[0][1] = USB_FUNCTION_SDB;
263 gadget->attrs.idProduct = 0x6860;
266 case USB_FUNCTION_MTP | USB_FUNCTION_SDB:
268 functions[0][0] = USB_FUNCTION_MTP;
269 functions[0][1] = USB_FUNCTION_SDB;
271 gadget->attrs.idProduct = 0x6860;
274 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
276 functions[0][0] = USB_FUNCTION_MTP;
277 functions[0][1] = USB_FUNCTION_ACM;
278 functions[0][2] = USB_FUNCTION_SDB;
280 gadget->attrs.idProduct = 0x6860;
283 case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB:
285 functions[0][0] = USB_FUNCTION_RNDIS;
286 functions[0][1] = USB_FUNCTION_SDB;
288 gadget->attrs.idProduct = 0x6864;
292 case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DIAG:
294 functions[0][0] = USB_FUNCTION_MTP;
295 functions[0][1] = USB_FUNCTION_ACM;
296 functions[0][2] = USB_FUNCTION_SDB;
297 functions[0][3] = USB_FUNCTION_DIAG;
299 gadget->attrs.idProduct = 0x6860;
302 case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM | USB_FUNCTION_DIAG:
304 functions[0][0] = USB_FUNCTION_RNDIS;
305 functions[0][1] = USB_FUNCTION_SDB;
306 functions[0][2] = USB_FUNCTION_ACM;
307 functions[0][3] = USB_FUNCTION_DIAG;
309 gadget->attrs.idProduct = 0x6864;
312 case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
314 functions[0][0] = USB_FUNCTION_RNDIS;
315 functions[0][1] = USB_FUNCTION_DIAG;
317 gadget->attrs.idProduct = 0x6864;
321 case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
323 functions[0][0] = USB_FUNCTION_ACM;
324 functions[0][1] = USB_FUNCTION_SDB;
325 functions[0][2] = USB_FUNCTION_DM;
327 gadget->attrs.idProduct = 0x6860;
330 case USB_FUNCTION_DIAG | USB_FUNCTION_ACM | USB_FUNCTION_RMNET:
332 functions[0][0] = USB_FUNCTION_DIAG;
333 functions[0][1] = USB_FUNCTION_ACM;
334 functions[0][2] = USB_FUNCTION_RMNET;
336 gadget->attrs.idProduct = 0x685d;
339 case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM:
341 functions[0][0] = USB_FUNCTION_RNDIS;
342 functions[0][1] = USB_FUNCTION_SDB;
343 functions[0][2] = USB_FUNCTION_ACM;
345 gadget->attrs.idProduct = 0x6864;
349 if (n_configs > 2 || n_configs <= 0) {
354 n_functions = __builtin_popcount(gadget_id->function_mask);
356 funcs = calloc(n_functions + 1, sizeof(*funcs));
362 gadget->funcs = funcs;
365 for (i = 0; _available_funcs[i]; ++i) {
366 int func_id = 1 << i;
368 if (!(gadget_id->function_mask & func_id))
371 ret = _available_funcs[i]->clone(_available_funcs[i],
372 gadget->funcs + idx);
378 for (j = 0; j < n_configs; ++j) {
379 struct usb_configuration *config;
380 int n_funcs_in_config;
382 for (i = 0; functions[j][i]; ++i);
383 n_funcs_in_config = i;
385 ret = alloc_default_config(&config);
389 gadget->configs[j] = config;
390 config->funcs = calloc(n_funcs_in_config + 1,
395 for (i = 0; functions[j][i]; ++i)
396 config->funcs[i] = find_func(gadget, functions[j][i]);
404 simple_cleanup_gadget(gadget);
409 void rndis_handler(int enable)
412 (void)systemd_start_unit_wait_started("rndis.service", NULL, -1);
414 (void)systemd_stop_unit_wait_stopped("rndis.service", NULL, -1);
417 static void free_simple_func(struct usb_function *func)
420 free((void *)func->name);
421 free((void *)func->instance);
422 free((void *)func->ffs_service);
423 free((void *)func->service);
428 static int clone_simple_func(struct usb_function *func,
429 struct usb_function **clone)
431 struct usb_function *other;
436 other = (struct usb_function *)calloc(1, sizeof(struct usb_function));
442 other->name = strdup(func->name);
443 other->instance = strdup(func->instance);
444 if (!other->name || !other->instance)
447 if (func->ffs_service) {
448 other->ffs_service = strdup(func->ffs_service);
449 if (!other->ffs_service)
454 other->service = strdup(func->service);
463 free_simple_func(other);
467 #define DEFINE_USB_FUNCTION(_id, _name, _ffs_service, _service, _handler) \
468 static struct usb_function _##_name##_function = { \
471 .instance = "default", \
472 .ffs_service = _ffs_service, \
473 .service = _service, \
474 .handler = _handler, \
475 .clone = clone_simple_func, \
476 .free_func = free_simple_func, \
479 DEFINE_USB_FUNCTION(USB_FUNCTION_DIAG, diag, NULL, NULL, NULL);
480 DEFINE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet, NULL, NULL, NULL);
481 DEFINE_USB_FUNCTION(USB_FUNCTION_DM, dm, NULL, NULL, NULL);
482 DEFINE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget, NULL, NULL, NULL);
483 DEFINE_USB_FUNCTION(USB_FUNCTION_SDB, sdb, "sdbd", NULL, NULL);
484 DEFINE_USB_FUNCTION(USB_FUNCTION_MTP, mtp, "mtp-responder", NULL, NULL);
485 DEFINE_USB_FUNCTION(USB_FUNCTION_ACM, acm, NULL, "data-router", NULL);
486 DEFINE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis, NULL, "sshd", rndis_handler);
487 #undef DEFINE_USB_FUNCTION
489 /* Caution: index order of arrary is important, because simple_id_to_gadget() uses it. */
490 struct usb_function *_available_funcs[] = {
491 [USB_FUNCTION_IDX_MTP] = &_mtp_function,
492 [USB_FUNCTION_IDX_ACM] = &_acm_function,
493 [USB_FUNCTION_IDX_SDB] = &_sdb_function,
494 [USB_FUNCTION_IDX_RNDIS] = &_rndis_function,
495 [USB_FUNCTION_IDX_DIAG] = &_diag_function,
496 [USB_FUNCTION_IDX_CONN_GADGET] = &_conn_gadget_function,
497 [USB_FUNCTION_IDX_DM] = &_dm_function,
498 [USB_FUNCTION_IDX_RMNET] = &_rmnet_function,
499 [USB_FUNCTION_IDX_MAX] = NULL /* An indicator to end the array */
503 int simple_translator_open(struct hw_info *info,
504 const char *id, struct hw_common **common)
506 struct usb_gadget_translator *simple_translator;
508 if (!info || !common)
511 simple_translator = zalloc(sizeof(*simple_translator));
512 if (!simple_translator)
515 simple_translator->common.info = info;
516 simple_translator->id_to_gadget = simple_id_to_gadget;
517 simple_translator->cleanup_gadget = simple_cleanup_gadget;
519 *common = &simple_translator->common;
524 int simple_translator_close(struct hw_common *common)
526 struct usb_gadget_translator *simple_translator;
531 simple_translator = container_of(common, struct usb_gadget_translator,
534 free(simple_translator);