summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb_gadget.h298
1 files changed, 298 insertions, 0 deletions
diff --git a/hw/usb_gadget.h b/hw/usb_gadget.h
new file mode 100644
index 0000000..2db9566
--- /dev/null
+++ b/hw/usb_gadget.h
@@ -0,0 +1,298 @@
+/*
+ * 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 <hw/common.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/**
+ * 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)
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#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;
+ char *name;
+ 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(func->name);
+ free(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(other->name);
+ free(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 = 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", \
+ .free_func = free_simple_func, \
+ .clone = clone_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(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 = 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) \
+ static struct usb_function_with_service _##_name##_function = { \
+ .func = { \
+ .function_group = USB_FUNCTION_GROUP_WITH_SERVICE, \
+ .id = _id, \
+ .name = #_name, \
+ .instance = "default", \
+ .free_func = free_func_with_service, \
+ .clone = clone_func_with_service, \
+ }, \
+ .service = NULL, \
+ }
+
+DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_SDB, sdb);
+DEFINE_USB_FUNCTION_WITH_SERVICE(USB_FUNCTION_MTP, mtp);
+
+#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);
+};
+
+#endif