/* * libdevice-node * * Copyright (c) 2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __HW_USB_GADGET_H__ #define __HW_USB_GADGET_H__ #include #include #include #include #include /** * The id of this device */ #define USB_GADGET_DEVICE_ID "usb_gadget" /** * The version of this device */ #define USB_GADGET_DEVICE_VERSION MAKE_VERSION(0,1) #define _HELPER_Y(x) ((x) & -(x)) /* Count number of trailing zeros using Dean Gaudet's algorithm */ #define _HELPER_CTZ(mask) \ ((_HELPER_Y(mask) ? 0 : 1) + \ ((_HELPER_Y(mask) & 0x0000FFFF) ? 0 : 16) + \ ((_HELPER_Y(mask) & 0x00FF00FF) ? 0 : 8) + \ ((_HELPER_Y(mask) & 0x0F0F0F0F) ? 0 : 4) + \ ((_HELPER_Y(mask) & 0x33333333) ? 0 : 2) + \ ((_HELPER_Y(mask) & 0x55555555) ? 0 : 1)) /* Function IDX in array is number of trailing zeros */ #define FUNC_IDX_FROM_MASK(mask) _HELPER_CTZ(mask) typedef enum { USB_FUNCTION_GROUP_SIMPLE, USB_FUNCTION_GROUP_WITH_SERVICE, } usb_function_group_e; struct usb_function { int function_group; int id; const char *name; const char *instance; int (*clone)(struct usb_function *func, struct usb_function **_clone); void (*free_func)(struct usb_function *func); }; struct usb_function_with_service { struct usb_function func; const char *service; }; struct usb_configuration_attributes { uint8_t bmAttributs; int MaxPower; }; struct usb_configuration_strings { uint16_t lang_code; char *config_str; }; struct usb_configuration { struct usb_configuration_attributes attrs; struct usb_configuration_strings *strs; struct usb_function **funcs; }; struct usb_gadget_attrs { uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; }; struct usb_gadget_strings { uint16_t lang_code; char *manufacturer; char *product; char *serial; }; struct usb_gadget { struct usb_gadget_attrs attrs; struct usb_gadget_strings *strs; struct usb_function **funcs; struct usb_configuration **configs; }; typedef enum { USB_FUNCTION_NONE = 0, USB_FUNCTION_MTP = 1 << 0, USB_FUNCTION_ACM = 1 << 1, USB_FUNCTION_SDB = 1 << 2, USB_FUNCTION_RNDIS = 1 << 3, USB_FUNCTION_DIAG = 1 << 4, USB_FUNCTION_CONN_GADGET = 1 << 5, USB_FUNCTION_DM = 1 << 6, USB_FUNCTION_RMNET = 1 << 7, } usb_function_e; static void free_simple_func_content(struct usb_function *func) { free((void *)func->name); free((void *)func->instance); } static void free_simple_func(struct usb_function *func) { free_simple_func_content(func); free(func); } static int clone_simple_func_to(struct usb_function *func, struct usb_function *other) { *other = *func; other->name = strdup(func->name); other->instance = strdup(func->instance); if (!other->name || !other->instance) goto free_strs; return 0; free_strs: free((void *)other->name); free((void *)other->instance); return -ENOMEM; } static int clone_simple_func(struct usb_function *func, struct usb_function **clone) { struct usb_function *other; int ret; if (!func || !clone) return -EINVAL; other = (struct usb_function *)malloc(sizeof(*other)); if (!other) goto out; ret = clone_simple_func_to(func, other); if (ret) goto free_other; *clone = other; return 0; free_other: free(other); out: return -ENOMEM; } #define DEFINE_SIMPLE_USB_FUNCTION(_id, _name) \ static struct usb_function _##_name##_function = { \ .function_group = USB_FUNCTION_GROUP_SIMPLE, \ .id = _id, \ .name = #_name, \ .instance = "default", \ .clone = clone_simple_func, \ .free_func = free_simple_func, \ } DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_ACM, acm); DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_RNDIS, rndis); DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_DIAG, diag); DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_RMNET, rmnet); DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_DM, dm); DEFINE_SIMPLE_USB_FUNCTION(USB_FUNCTION_CONN_GADGET, conn_gadget); #undef DEFINE_SIMPLE_USB_FUNCTION static void free_func_with_service(struct usb_function *func) { struct usb_function_with_service *fws; fws = container_of(func, struct usb_function_with_service, func); free_simple_func_content(func); free((void *)fws->service); free(fws); } static int clone_func_with_service(struct usb_function *func, struct usb_function **clone) { struct usb_function_with_service *fws; struct usb_function_with_service *other; int ret; if (!func || !clone) return -EINVAL; other = (struct usb_function_with_service *)malloc(sizeof(*other)); if (!other) goto out; ret = clone_simple_func_to(func, &other->func); if (ret) goto free_other; fws = container_of(func, struct usb_function_with_service, func); if (fws->service) { other->service = strdup(fws->service); if (!other->service) goto free_content; } else { other->service = NULL; } *clone = &other->func; return 0; free_content: free_simple_func_content(&other->func); free_other: free(other); out: return -ENOMEM; } #define DEFINE_USB_FUNCTION_WITH_SERVICE(_id, _name, _service) \ static struct usb_function_with_service _##_name##_function = { \ .func = { \ .function_group = USB_FUNCTION_GROUP_WITH_SERVICE, \ .id = _id, \ .name = #_name, \ .instance = "default", \ .clone = clone_func_with_service, \ .free_func = free_func_with_service, \ }, \ .service = _service, \ } DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_SDB, sdb, "sdbd"); DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_MTP, mtp, "mtp-responder"); #define MAKE_FUNC_AVAILABLE(_name, _vname) \ [FUNC_IDX_FROM_MASK(USB_FUNCTION_##_name)] = &_##_vname##_function #define MAKE_FUNC_WS_AVAILABLE(_name, _vname) \ [FUNC_IDX_FROM_MASK(USB_FUNCTION_##_name)] = &_##_vname##_function.func static struct usb_function *_available_funcs[] = { MAKE_FUNC_WS_AVAILABLE(MTP, mtp), MAKE_FUNC_AVAILABLE(ACM, acm), MAKE_FUNC_WS_AVAILABLE(SDB, sdb), MAKE_FUNC_AVAILABLE(RNDIS, rndis), MAKE_FUNC_AVAILABLE(DIAG, diag), MAKE_FUNC_AVAILABLE(CONN_GADGET, conn_gadget), MAKE_FUNC_AVAILABLE(DM, dm), MAKE_FUNC_AVAILABLE(RMNET, rmnet), }; #undef MAKE_FUNC_AVAILABLE struct usb_gadget_id { unsigned int function_mask; }; struct usb_gadget_translator { struct hw_common common; int (*id_to_gadget)(struct usb_gadget_id *gadget_id, struct usb_gadget **gadget); void (*cleanup_gadget)(struct usb_gadget *gadget); }; int simple_translator_open(struct hw_info *info, const char *id, struct hw_common **common); int simple_translator_close(struct hw_common *common); #endif