diff --git a/include/usbg/usbg_internal.h b/include/usbg/usbg_internal.h index be53915..7f048a6 100644 --- a/include/usbg/usbg_internal.h +++ b/include/usbg/usbg_internal.h @@ -46,6 +46,14 @@ struct usbg_function_type /* Name of this function type */ char *name; + /* Called to allocate instance of function */ + int (*alloc_inst)(struct usbg_function_type *, usbg_function_type, + const char *, const char *, usbg_gadget *, + struct usbg_function **); + + /* Called to free memory used by function */ + void (*free_inst)(struct usbg_function_type *, struct usbg_function *); + /* * Called when user would like to remove this function. * If this callback is provided it will be always called @@ -252,6 +260,55 @@ int usbg_check_dir(const char *path); #define usbg_config_is_string(node) \ (config_setting_type(node) == CONFIG_TYPE_STRING) +int usbg_init_function(struct usbg_function *f, + struct usbg_function_type *ops, + usbg_function_type type, + const char *type_name, + const char *instance, + const char *path, + struct usbg_gadget *parent); + +int usbg_cleanup_function(struct usbg_function *f); + +#define GENERIC_ALLOC_INST(prefix, _type, _member) \ + static int prefix##_alloc_inst(struct usbg_function_type *type, \ + usbg_function_type type_code, \ + const char *instance, const char *path, \ + struct usbg_gadget *parent, \ + struct usbg_function **f) \ + { \ + _type *ff; \ + int ret; \ + \ + ff = malloc(sizeof(*ff)); \ + if (!ff) \ + return USBG_ERROR_NO_MEM; \ + \ + ret = usbg_init_function(&ff->_member, type, type_code, \ + type->name, instance, path, parent); \ + if (ret != USBG_SUCCESS) \ + goto free_func; \ + \ + *f = &ff->_member; \ + \ + return ret; \ + \ + free_func: \ + free(ff); \ + out: \ + return ret; \ + } + +#define GENERIC_FREE_INST(prefix, _type, _member) \ + static void prefix##_free_inst(struct usbg_function_type *type, \ + struct usbg_function *f) \ + { \ + _type *ff = container_of(f, _type, _member); \ + \ + usbg_cleanup_function(&ff->_member); \ + free(ff); \ + } + typedef int (*usbg_attr_get_func)(const char *, const char *, const char *, void *); typedef int (*usbg_attr_set_func)(const char *, const char *, const char *, void *); diff --git a/src/function/ether.c b/src/function/ether.c index ca9dee7..a778aee 100644 --- a/src/function/ether.c +++ b/src/function/ether.c @@ -18,6 +18,14 @@ #include #endif +struct usbg_f_ether { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(ether, struct usbg_f_ether, func); + +GENERIC_FREE_INST(ether, struct usbg_f_ether, func); + static int ether_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -216,6 +224,8 @@ out: #endif /* HAS_LIBCONFIG */ #define ETHER_FUNCTION_OPTS \ + .alloc_inst = ether_alloc_inst, \ + .free_inst = ether_free_inst, \ .set_attrs = ether_set_attrs, \ .get_attrs = ether_get_attrs, \ .cleanup_attrs = ether_cleanup_attrs, \ diff --git a/src/function/ffs.c b/src/function/ffs.c index 05f750d..ba255c8 100644 --- a/src/function/ffs.c +++ b/src/function/ffs.c @@ -17,6 +17,14 @@ #include #endif +struct usbg_f_fs { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(ffs, struct usbg_f_fs, func); + +GENERIC_FREE_INST(ffs, struct usbg_f_fs, func); + static int ffs_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -72,6 +80,8 @@ static int ffs_libconfig_export(struct usbg_function *f, struct usbg_function_type usbg_f_type_ffs = { .name = "ffs", + .alloc_inst = ffs_alloc_inst, + .free_inst = ffs_free_inst, .set_attrs = ffs_set_attrs, .get_attrs = ffs_get_attrs, .cleanup_attrs = ffs_cleanup_attrs, diff --git a/src/function/loopback.c b/src/function/loopback.c index 178e5e8..13a61b1 100644 --- a/src/function/loopback.c +++ b/src/function/loopback.c @@ -17,6 +17,14 @@ #include #endif +struct usbg_f_loopback { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(loopback, struct usbg_f_loopback, func); + +GENERIC_FREE_INST(loopback, struct usbg_f_loopback, func); + static int loopback_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -141,6 +149,8 @@ out: struct usbg_function_type usbg_f_type_loopback = { .name = "loopback", + .alloc_inst = loopback_alloc_inst, + .free_inst = loopback_free_inst, .set_attrs = loopback_set_attrs, .get_attrs = loopback_get_attrs, #ifdef HAS_LIBCONFIG diff --git a/src/function/midi.c b/src/function/midi.c index a377c73..b0e7b27 100644 --- a/src/function/midi.c +++ b/src/function/midi.c @@ -18,6 +18,14 @@ #include #endif +struct usbg_f_midi { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(midi, struct usbg_f_midi, func); + +GENERIC_FREE_INST(midi, struct usbg_f_midi, func); + static int midi_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -216,6 +224,8 @@ out: struct usbg_function_type usbg_f_type_midi = { .name = "midi", + .alloc_inst = midi_alloc_inst, + .free_inst = midi_free_inst, .set_attrs = midi_set_attrs, .get_attrs = midi_get_attrs, .cleanup_attrs = midi_cleanup_attrs, diff --git a/src/function/ms.c b/src/function/ms.c index 40797f1..85695a9 100644 --- a/src/function/ms.c +++ b/src/function/ms.c @@ -21,6 +21,14 @@ #include #endif +struct usbg_f_ms { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(ms, struct usbg_f_ms, func); + +GENERIC_FREE_INST(ms, struct usbg_f_ms, func); + static inline int lun_select(const struct dirent *dent) { int ret; @@ -652,6 +660,8 @@ out: struct usbg_function_type usbg_f_type_ms = { .name = "mass_storage", + .alloc_inst = ms_alloc_inst, + .free_inst = ms_free_inst, .set_attrs = ms_set_attrs, .get_attrs = ms_get_attrs, .cleanup_attrs = ms_cleanup_attrs, diff --git a/src/function/phonet.c b/src/function/phonet.c index 57484f9..3858343 100644 --- a/src/function/phonet.c +++ b/src/function/phonet.c @@ -18,6 +18,14 @@ #include #endif +struct usbg_f_phonet { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(phonet, struct usbg_f_phonet, func); + +GENERIC_FREE_INST(phonet, struct usbg_f_phonet, func); + static int phonet_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -71,6 +79,8 @@ static int phonet_libconfig_export(struct usbg_function *f, struct usbg_function_type usbg_f_type_phonet = { .name = "phonet", + .alloc_inst = phonet_alloc_inst, + .free_inst = phonet_free_inst, .set_attrs = phonet_set_attrs, .get_attrs = phonet_get_attrs, .cleanup_attrs = phonet_cleanup_attrs, diff --git a/src/function/serial.c b/src/function/serial.c index e4f1130..118903e 100644 --- a/src/function/serial.c +++ b/src/function/serial.c @@ -17,6 +17,14 @@ #include #endif +struct usbg_f_serial { + struct usbg_function func; +}; + +GENERIC_ALLOC_INST(serial, struct usbg_f_serial, func); + +GENERIC_FREE_INST(serial, struct usbg_f_serial, func); + static int serial_set_attrs(struct usbg_function *f, const usbg_function_attrs *f_attrs) { @@ -92,8 +100,10 @@ static int serial_libconfig_import(struct usbg_function *f, /* We don' import port_num as it is read only */ #define SERIAL_FUNCTION_OPTS \ - .set_attrs = serial_set_attrs, \ - .get_attrs = serial_get_attrs, \ + .alloc_inst = serial_alloc_inst, \ + .free_inst = serial_free_inst, \ + .set_attrs = serial_set_attrs, \ + .get_attrs = serial_get_attrs, \ SERIAL_LIBCONFIG_DEP_OPS, \ .import = serial_libconfig_import diff --git a/src/usbg.c b/src/usbg.c index 8856b4d..ca0cd78 100644 --- a/src/usbg.c +++ b/src/usbg.c @@ -284,10 +284,8 @@ static inline void usbg_free_binding(usbg_binding *b) static inline void usbg_free_function(usbg_function *f) { - free(f->path); - free(f->name); - free(f->label); - free(f); + if (f->ops->free_inst) + f->ops->free_inst(f->ops, f); } static void usbg_free_config(usbg_config *c) @@ -426,46 +424,16 @@ out: return c; } -static usbg_function *usbg_allocate_function(const char *path, - usbg_function_type type, const char *instance, usbg_gadget *parent) +static usbg_function * +usbg_allocate_function(const char *path, usbg_function_type type, + const char *instance, usbg_gadget *parent) { usbg_function *f; - const char *type_name; int ret; - f = malloc(sizeof(*f)); - if (!f) - goto out; - - f->label = NULL; - type_name = usbg_get_function_type_str(type); - if (!type_name) { - free(f); - f = NULL; - goto out; - } - - ret = asprintf(&(f->name), "%s.%s", type_name, instance); - if (ret < 0) { - free(f); - f = NULL; - goto out; - } - f->instance = f->name + strlen(type_name) + 1; - f->path = strdup(path); - f->parent = parent; - f->type = type; - f->ops = function_types[type]; - - if (!(f->path)) { - free(f->name); - free(f->path); - free(f); - f = NULL; - } - -out: - return f; + ret = function_types[type]->alloc_inst(function_types[type], type, + instance, path, parent, &f); + return ret == 0 ? f : NULL; } static usbg_binding *usbg_allocate_binding(const char *path, const char *name, diff --git a/src/usbg_common.c b/src/usbg_common.c index 69472e2..a4d9933 100644 --- a/src/usbg_common.c +++ b/src/usbg_common.c @@ -265,7 +265,30 @@ int usbg_check_dir(const char *path) return ret; } +int usbg_init_function(struct usbg_function *f, + struct usbg_function_type *ops, + usbg_function_type type, + const char *type_name, + const char *instance, + const char *path, + struct usbg_gadget *parent) +{ + int ret; + ret = asprintf(&(f->name), "%s.%s", type_name, instance); + if (ret < 0) + return USBG_ERROR_NO_MEM; + + f->instance = f->name + strlen(type_name) + 1; + f->path = strdup(path); + f->parent = parent; + f->type = type; + f->ops = ops; + f->label = NULL; + memset(&f->fnode, 0, sizeof(f->fnode)); + + return 0; +} int usbg_get_ether_addr(const char *path, const char *name, const char *attr, void *val) @@ -423,3 +446,9 @@ int usbg_set_config_node_ether_addr(config_setting_t *root, return usbg_set_config_node_string(root, node_name, &ptr); } +int usbg_cleanup_function(struct usbg_function *f) +{ + free(f->path); + free(f->name); + free(f->label); +}