2010-07-23 11:55:18 +00:00
|
|
|
// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
|
|
|
|
#ifndef BRICK_H
|
|
|
|
#define BRICK_H
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
#ifdef _STRATEGY
|
|
|
|
#define _STRATEGY_CODE(X) X
|
|
|
|
#define _NORMAL_CODE(X) /**/
|
|
|
|
#else
|
|
|
|
#define _STRATEGY_CODE(X) /**/
|
|
|
|
#define _NORMAL_CODE(X) X
|
|
|
|
#endif
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#define BRICK_ERROR "BRICK_ERROR " __BASE_FILE__ ": "
|
|
|
|
#define BRICK_INFO "BRICK_INFO " __BASE_FILE__ ": "
|
|
|
|
#define BRICK_DEBUG "BRICK_DEBUG " __BASE_FILE__ ": "
|
2010-07-23 11:55:18 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#define BRICK_ERR(fmt, args...) printk(BRICK_ERROR "%s(): " fmt, __FUNCTION__, ##args)
|
|
|
|
#define BRICK_INF(fmt, args...) printk(BRICK_INFO "%s(): " fmt, __FUNCTION__, ##args)
|
2010-07-23 11:55:18 +00:00
|
|
|
#ifdef BRICK_DEBUGGING
|
2010-07-30 05:46:22 +00:00
|
|
|
#define BRICK_DBG(fmt, args...) printk(BRICK_DEBUG "%s(): " fmt, __FUNCTION__, ##args)
|
2010-07-23 11:55:18 +00:00
|
|
|
#else
|
|
|
|
#define BRICK_DBG(args...) /**/
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MAX_BRICK_TYPES 64
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// definitions for generic objects with aspects
|
|
|
|
|
|
|
|
#define MAX_DEFAULT_ASPECTS 8
|
|
|
|
|
|
|
|
struct generic_aspect;
|
|
|
|
|
|
|
|
#define GENERIC_ASPECT_TYPE(PREFIX) \
|
|
|
|
char *aspect_type_name; \
|
2010-07-30 05:46:22 +00:00
|
|
|
const struct generic_object_type *object_type; \
|
2010-07-23 11:55:18 +00:00
|
|
|
int aspect_size; \
|
|
|
|
int (*init_fn)(struct generic_aspect *ini, void *data); \
|
|
|
|
|
|
|
|
struct generic_aspect_type {
|
|
|
|
GENERIC_ASPECT_TYPE(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_ASPECT_LAYOUT(PREFIX) \
|
|
|
|
const struct generic_aspect_type *aspect_type; \
|
|
|
|
void *init_data; \
|
2010-07-30 05:46:22 +00:00
|
|
|
int aspect_offset; \
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
struct generic_aspect_layout {
|
|
|
|
GENERIC_ASPECT_LAYOUT(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OBJECT_TYPE(PREFIX) \
|
|
|
|
char *object_type_name; \
|
|
|
|
int default_size; \
|
|
|
|
int brick_obj_nr; \
|
|
|
|
|
|
|
|
struct generic_object_type {
|
|
|
|
GENERIC_OBJECT_TYPE(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OBJECT_LAYOUT(PREFIX) \
|
|
|
|
const struct generic_object_type *object_type; \
|
|
|
|
int object_size; \
|
|
|
|
int rest_size; \
|
2010-07-30 05:46:22 +00:00
|
|
|
int aspect_count; \
|
|
|
|
struct generic_aspect_layout *aspect_layouts[]; \
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
struct generic_object_layout {
|
|
|
|
GENERIC_OBJECT_LAYOUT(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OBJECT(PREFIX) \
|
|
|
|
struct PREFIX##_object_layout *object_layout; \
|
|
|
|
int object_size; \
|
|
|
|
|
|
|
|
struct generic_object {
|
|
|
|
GENERIC_OBJECT(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_ASPECT(PREFIX) \
|
|
|
|
struct PREFIX##_object *object; \
|
|
|
|
|
|
|
|
struct generic_aspect {
|
|
|
|
GENERIC_ASPECT(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// definitions for generic bricks
|
|
|
|
|
|
|
|
struct generic_input;
|
|
|
|
struct generic_output;
|
|
|
|
struct generic_brick_ops;
|
|
|
|
struct generic_output_ops;
|
|
|
|
struct generic_brick_type;
|
|
|
|
|
|
|
|
#define GENERIC_BRICK(PREFIX) \
|
|
|
|
char *brick_name; \
|
|
|
|
const struct PREFIX##_brick_type *type; \
|
|
|
|
struct PREFIX##_brick_ops *ops; \
|
|
|
|
int nr_inputs; \
|
|
|
|
int nr_outputs; \
|
|
|
|
struct PREFIX##_input **inputs; \
|
|
|
|
struct PREFIX##_output **outputs; \
|
|
|
|
struct list_head tmp_head; \
|
|
|
|
|
|
|
|
struct generic_brick {
|
|
|
|
GENERIC_BRICK(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_INPUT(PREFIX) \
|
|
|
|
char *input_name; \
|
|
|
|
struct PREFIX##_brick *brick; \
|
|
|
|
const struct PREFIX##_input_type *type; \
|
|
|
|
struct PREFIX##_output *connect; \
|
2010-07-30 05:46:22 +00:00
|
|
|
struct list_head input_head; \
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
struct generic_input {
|
|
|
|
GENERIC_INPUT(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OUTPUT(PREFIX) \
|
|
|
|
char *output_name; \
|
|
|
|
struct PREFIX##_brick *brick; \
|
|
|
|
const struct PREFIX##_output_type *type; \
|
|
|
|
struct PREFIX##_output_ops *ops; \
|
2010-07-30 05:46:22 +00:00
|
|
|
struct list_head output_head; \
|
2010-07-23 11:55:18 +00:00
|
|
|
int nr_connected; \
|
|
|
|
/* _must_ be the last member */ \
|
|
|
|
struct generic_aspect_layout aspect_layouts[BRICK_OBJ_NR]; \
|
|
|
|
|
|
|
|
struct generic_output {
|
|
|
|
GENERIC_OUTPUT(generic);
|
|
|
|
};
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#define GENERIC_OUTPUT_CALL(OUTPUT,OP,ARGS...) \
|
|
|
|
( \
|
|
|
|
LOCK_CHECK(OP), \
|
|
|
|
(OUTPUT) && (OUTPUT)->ops->OP ? \
|
|
|
|
(OUTPUT)->ops->OP(OUTPUT, ##ARGS) : \
|
|
|
|
-ENOSYS \
|
|
|
|
)
|
|
|
|
|
|
|
|
#define GENERIC_INPUT_CALL(INPUT,OP,ARGS...) \
|
|
|
|
( \
|
|
|
|
LOCK_CHECK(OP), \
|
|
|
|
(INPUT) && (INPUT)->connect ? \
|
|
|
|
GENERIC_OUTPUT_CALL((INPUT)->connect, OP, ##ARGS) : \
|
|
|
|
-ENOSYS \
|
|
|
|
)
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
#define GENERIC_BRICK_OPS(PREFIX) \
|
|
|
|
/*int (*brick_start)(struct PREFIX##_brick *brick);*/ \
|
|
|
|
/*int (*brick_stop)(struct PREFIX##_brick *brick);*/ \
|
|
|
|
|
|
|
|
struct generic_brick_ops {
|
|
|
|
GENERIC_BRICK_OPS(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OUTPUT_OPS(PREFIX) \
|
|
|
|
/*int (*output_start)(struct PREFIX##_output *output);*/ \
|
|
|
|
/*int (*output_stop)(struct PREFIX##_output *output);*/ \
|
|
|
|
int (*make_object_layout)(struct PREFIX##_output *output, struct generic_object_layout *object_layout); \
|
|
|
|
|
|
|
|
struct generic_output_ops {
|
|
|
|
GENERIC_OUTPUT_OPS(generic)
|
|
|
|
};
|
|
|
|
|
|
|
|
// although possible, *_type should never be extended
|
|
|
|
#define GENERIC_BRICK_TYPE(PREFIX) \
|
|
|
|
char *type_name; \
|
|
|
|
int brick_size; \
|
|
|
|
int max_inputs; \
|
|
|
|
int max_outputs; \
|
|
|
|
const struct PREFIX##_input_type **default_input_types; \
|
|
|
|
char **default_input_names; \
|
|
|
|
const struct PREFIX##_output_type **default_output_types; \
|
|
|
|
char **default_output_names; \
|
|
|
|
struct PREFIX##_brick_ops *master_ops; \
|
|
|
|
const struct PREFIX##input_types **default_type; \
|
|
|
|
int (*brick_construct)(struct PREFIX##_brick *brick); \
|
|
|
|
int (*brick_destruct)(struct PREFIX##_brick *brick); \
|
|
|
|
|
|
|
|
struct generic_brick_type {
|
|
|
|
GENERIC_BRICK_TYPE(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_INPUT_TYPE(PREFIX) \
|
|
|
|
char *type_name; \
|
|
|
|
int input_size; \
|
|
|
|
int (*input_construct)(struct PREFIX##_input *input); \
|
|
|
|
int (*input_destruct)(struct PREFIX##_input *input); \
|
|
|
|
|
|
|
|
struct generic_input_type {
|
|
|
|
GENERIC_INPUT_TYPE(generic);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GENERIC_OUTPUT_TYPE(PREFIX) \
|
|
|
|
char *type_name; \
|
|
|
|
int output_size; \
|
|
|
|
struct PREFIX##_output_ops *master_ops; \
|
|
|
|
int (*output_construct)(struct PREFIX##_output *output); \
|
|
|
|
int (*output_destruct)(struct PREFIX##_output *output); \
|
2010-07-30 05:46:22 +00:00
|
|
|
const struct generic_aspect_type **aspect_types; \
|
|
|
|
const int layout_code[BRICK_OBJ_NR]; \
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
struct generic_output_type {
|
|
|
|
GENERIC_OUTPUT_TYPE(generic);
|
|
|
|
};
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#define LAYOUT_NONE 0
|
|
|
|
#define LAYOUT_ALL -1
|
|
|
|
#define LAYOUT_1(X1) ((X1) | 255 << 8)
|
|
|
|
#define LAYOUT_2(X1,X2) ((X1) | (X2) << 8 | 255 << 16)
|
|
|
|
#define LAYOUT_3(X1,X2,X3) ((X1) | (X2) << 8 | (X3) << 16 | 255 << 24)
|
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
int generic_register_brick_type(const struct generic_brick_type *new_type);
|
|
|
|
int generic_unregister_brick_type(const struct generic_brick_type *old_type);
|
|
|
|
|
|
|
|
#ifdef _STRATEGY // call this only in strategy bricks, never in ordinary bricks
|
|
|
|
|
|
|
|
// you need this only if you circumvent generic_brick_init_full()
|
|
|
|
extern inline int generic_brick_init(const struct generic_brick_type *type, struct generic_brick *brick, char *brick_name)
|
|
|
|
{
|
|
|
|
brick->brick_name = brick_name;
|
|
|
|
brick->type = type;
|
|
|
|
brick->ops = type->master_ops;
|
|
|
|
brick->nr_inputs = 0;
|
|
|
|
brick->nr_outputs = 0;
|
|
|
|
brick->tmp_head.next = brick->tmp_head.prev = &brick->tmp_head;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern inline int generic_input_init(struct generic_brick *brick, int index, const struct generic_input_type *type, struct generic_input *input, char *input_name)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= brick->type->max_inputs)
|
|
|
|
return -ENOMEM;
|
|
|
|
if (brick->inputs[index])
|
|
|
|
return -EEXIST;
|
|
|
|
input->input_name = input_name;
|
|
|
|
input->brick = brick;
|
|
|
|
input->type = type;
|
|
|
|
input->connect = NULL;
|
|
|
|
brick->inputs[index] = input;
|
|
|
|
brick->nr_inputs++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern inline int generic_output_init(struct generic_brick *brick, int index, const struct generic_output_type *type, struct generic_output *output, char *output_name)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= brick->type->max_outputs)
|
|
|
|
return -ENOMEM;
|
|
|
|
if (brick->outputs[index])
|
|
|
|
return -EEXIST;
|
|
|
|
output->output_name = output_name;
|
|
|
|
output->brick = brick;
|
|
|
|
output->type = type;
|
|
|
|
output->ops = type->master_ops;
|
|
|
|
output->nr_connected = 0;
|
|
|
|
brick->outputs[index] = output;
|
|
|
|
brick->nr_outputs++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern inline int generic_size(const struct generic_brick_type *brick_type)
|
|
|
|
{
|
|
|
|
int size = brick_type->brick_size;
|
|
|
|
int i;
|
|
|
|
size += brick_type->max_inputs * sizeof(void*);
|
|
|
|
for (i = 0; i < brick_type->max_inputs; i++) {
|
|
|
|
size += brick_type->default_input_types[i]->input_size;
|
|
|
|
}
|
|
|
|
size += brick_type->max_outputs * sizeof(void*);
|
|
|
|
for (i = 0; i < brick_type->max_outputs; i++) {
|
|
|
|
size += brick_type->default_output_types[i]->output_size;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If possible, use this instead of generic_*_init().
|
|
|
|
* input_types and output_types may be NULL => use default_*_types
|
|
|
|
*/
|
|
|
|
int generic_brick_init_full(
|
|
|
|
void *data,
|
|
|
|
int size,
|
|
|
|
const struct generic_brick_type *brick_type,
|
|
|
|
const struct generic_input_type **input_types,
|
|
|
|
const struct generic_output_type **output_types,
|
|
|
|
char **names);
|
|
|
|
|
|
|
|
int generic_brick_exit_full(
|
|
|
|
struct generic_brick *brick);
|
|
|
|
|
|
|
|
extern inline int generic_connect(struct generic_input *input, struct generic_output *output)
|
|
|
|
{
|
|
|
|
BRICK_DBG("generic_connect(input=%p, output=%p)\n", input, output);
|
|
|
|
if (!input || !output)
|
|
|
|
return -EINVAL;
|
|
|
|
if (input->connect)
|
|
|
|
return -EEXIST;
|
|
|
|
input->connect = output;
|
|
|
|
output->nr_connected++; //TODO: protect against races, e.g. atomic_t
|
|
|
|
BRICK_DBG("now nr_connected=%d\n", output->nr_connected);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern inline int generic_disconnect(struct generic_input *input)
|
|
|
|
{
|
|
|
|
BRICK_DBG("generic_disconnect(input=%p)\n", input);
|
|
|
|
if (!input)
|
|
|
|
return -EINVAL;
|
|
|
|
if (input->connect) {
|
|
|
|
input->connect->nr_connected--; //TODO: protect against races, e.g. atomic_t
|
|
|
|
BRICK_DBG("now nr_connected=%d\n", input->connect->nr_connected);
|
|
|
|
input->connect = NULL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // _STRATEGY
|
|
|
|
|
|
|
|
// simple wrappers for type safety
|
|
|
|
#define GENERIC_MAKE_FUNCTIONS(PREFIX) \
|
|
|
|
extern inline int PREFIX##_register_brick_type(void) \
|
|
|
|
{ \
|
|
|
|
extern const struct PREFIX##_brick_type PREFIX##_brick_type; \
|
|
|
|
extern int PREFIX##_brick_nr; \
|
|
|
|
if (PREFIX##_brick_nr >= 0) { \
|
|
|
|
BRICK_ERR("brick type " #PREFIX " is already registered.\n"); \
|
|
|
|
return -EEXIST; \
|
|
|
|
} \
|
|
|
|
PREFIX##_brick_nr = generic_register_brick_type((const struct generic_brick_type*)&PREFIX##_brick_type); \
|
|
|
|
return PREFIX##_brick_nr < 0 ? PREFIX##_brick_nr : 0; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
extern inline int PREFIX##_unregister_brick_type(void) \
|
|
|
|
{ \
|
|
|
|
extern const struct PREFIX##_brick_type PREFIX##_brick_type; \
|
|
|
|
return generic_unregister_brick_type((const struct generic_brick_type*)&PREFIX##_brick_type); \
|
|
|
|
} \
|
|
|
|
\
|
2010-07-30 05:46:22 +00:00
|
|
|
extern int PREFIX##_make_object_layout(struct PREFIX##_output *output, struct generic_object_layout *object_layout) \
|
|
|
|
{ \
|
|
|
|
return default_make_object_layout((struct generic_output*)output, object_layout); \
|
|
|
|
} \
|
|
|
|
\
|
2010-07-23 11:55:18 +00:00
|
|
|
_STRATEGY_CODE( \
|
|
|
|
extern const struct PREFIX##_brick_type PREFIX##_brick_type; \
|
|
|
|
extern const struct PREFIX##_input_type PREFIX##_input_type; \
|
|
|
|
extern const struct PREFIX##_output_type PREFIX##_output_type; \
|
|
|
|
\
|
|
|
|
static inline int PREFIX##_brick_init(struct PREFIX##_brick *brick, char *brick_name) \
|
|
|
|
{ \
|
|
|
|
return generic_brick_init((const struct generic_brick_type*)&PREFIX##_brick_type, (struct generic_brick*)brick, brick_name); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline int PREFIX##_input_init(struct PREFIX##_brick *brick, int index, struct PREFIX##_input *input, char *input_name) \
|
|
|
|
{ \
|
|
|
|
return generic_input_init( \
|
|
|
|
(struct generic_brick*)brick, \
|
|
|
|
index, \
|
|
|
|
(struct generic_input_type*)&PREFIX##_input_type, \
|
|
|
|
(struct generic_input*)input, \
|
|
|
|
input_name); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline int PREFIX##_output_init(struct PREFIX##_brick *brick, int index, struct PREFIX##_input *output, char *output_name) \
|
|
|
|
{ \
|
|
|
|
return generic_output_init( \
|
|
|
|
(struct generic_brick*)brick, \
|
|
|
|
index, \
|
|
|
|
(const struct generic_output_type*)&PREFIX##_output_type, \
|
|
|
|
(struct generic_output*)output, \
|
|
|
|
output_name); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
extern inline int PREFIX##_size(const struct PREFIX##_brick_type *brick_type) \
|
|
|
|
{ \
|
|
|
|
return generic_size((const struct generic_brick_type*)brick_type); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
extern inline int PREFIX##_brick_init_full( \
|
|
|
|
void *data, \
|
|
|
|
int size, \
|
|
|
|
const struct PREFIX##_brick_type *brick_type, \
|
|
|
|
const struct PREFIX##_input_type **input_types, \
|
|
|
|
const struct PREFIX##_output_type **output_types, \
|
|
|
|
char **names) \
|
|
|
|
{ \
|
|
|
|
return generic_brick_init_full( \
|
|
|
|
data, \
|
|
|
|
size, \
|
|
|
|
(const struct generic_brick_type*)brick_type, \
|
|
|
|
(const struct generic_input_type**)input_types, \
|
|
|
|
(const struct generic_output_type**)output_types, \
|
|
|
|
(char**)names); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
extern inline int PREFIX##_brick_exit_full( \
|
|
|
|
struct PREFIX##_brick *brick) \
|
|
|
|
{ \
|
|
|
|
return generic_brick_exit_full( \
|
|
|
|
(struct generic_brick*)brick); \
|
|
|
|
} \
|
|
|
|
)
|
|
|
|
|
|
|
|
/* Define a pair of connectable subtypes.
|
|
|
|
* For type safety, use this for all possible combinations.
|
|
|
|
* Yes, this may become quadratic in large type systems, but
|
|
|
|
* (a) thou shalt not define many types,
|
|
|
|
* (b) these macros generate only definitions, but no additional
|
|
|
|
* code at runtime.
|
|
|
|
*/
|
|
|
|
#define GENERIC_MAKE_CONNECT(INPUT_PREFIX,OUTPUT_PREFIX) \
|
|
|
|
\
|
|
|
|
_STRATEGY_CODE( \
|
|
|
|
\
|
|
|
|
extern inline int INPUT_PREFIX##_##OUTPUT_PREFIX##_connect( \
|
|
|
|
struct INPUT_PREFIX##_input *input, \
|
|
|
|
struct OUTPUT_PREFIX##_output *output) \
|
|
|
|
{ \
|
|
|
|
return generic_connect((struct generic_input*)input, (struct generic_output*)output); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
extern inline int INPUT_PREFIX##_##OUTPUT_PREFIX####_disconnect( \
|
|
|
|
struct INPUT_PREFIX##_input *input) \
|
|
|
|
{ \
|
|
|
|
return generic_disconnect((struct generic_input*)input); \
|
|
|
|
} \
|
|
|
|
)
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// default operations on objects / aspects
|
|
|
|
|
|
|
|
extern int default_make_object_layout(struct generic_output *output, struct generic_object_layout *object_layout);
|
|
|
|
|
|
|
|
extern inline int generic_add_aspect(struct generic_output *output, struct generic_object_layout *object_layout, const struct generic_aspect_type *aspect_type)
|
|
|
|
{
|
|
|
|
int nr = object_layout->object_type->brick_obj_nr;
|
|
|
|
struct generic_aspect_layout *aspect_layout;
|
|
|
|
aspect_layout = (void*)&output->aspect_layouts[nr];
|
|
|
|
if (object_layout->rest_size < sizeof(void*))
|
|
|
|
return -ENOMEM;
|
|
|
|
if (aspect_layout->aspect_type) {
|
|
|
|
/* aspect_layout is already initialized.
|
|
|
|
* this is a kind of "dynamic programming".
|
|
|
|
* ensure consistency to last call.
|
|
|
|
*/
|
|
|
|
int min_offset;
|
|
|
|
if (aspect_layout->aspect_type != aspect_type) {
|
|
|
|
BRICK_ERR("inconsistent use of aspect_type %s != %s\n", aspect_type->aspect_type_name, aspect_layout->aspect_type->aspect_type_name);
|
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
if (aspect_layout->init_data != output) {
|
|
|
|
BRICK_ERR("inconsistent output assigment (aspect_type=%s)\n", aspect_type->aspect_type_name);
|
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
min_offset = aspect_layout->aspect_offset + aspect_type->aspect_size;
|
|
|
|
if (object_layout->object_size > min_offset) {
|
|
|
|
BRICK_ERR("overlapping aspects %d > %d (aspect_type=%s)\n", object_layout->object_size, min_offset, aspect_type->aspect_type_name);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
BRICK_DBG("adjusting object_size %d to %d (aspect_type=%s)\n", object_layout->object_size, min_offset, aspect_type->aspect_type_name);
|
|
|
|
object_layout->object_size = min_offset;
|
|
|
|
} else {
|
|
|
|
/* first call: initialize aspect_layout. */
|
|
|
|
aspect_layout->aspect_type = aspect_type;
|
|
|
|
aspect_layout->init_data = output;
|
|
|
|
aspect_layout->aspect_offset = object_layout->object_size;
|
|
|
|
object_layout->object_size += aspect_type->aspect_size;
|
|
|
|
}
|
|
|
|
nr = object_layout->aspect_count++;
|
|
|
|
object_layout->aspect_layouts[nr] = aspect_layout;
|
|
|
|
object_layout->rest_size -= sizeof(void*);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GENERIC_OBJECT_LAYOUT_FUNCTIONS(PREFIX) \
|
|
|
|
\
|
|
|
|
extern inline struct PREFIX##_object_layout *PREFIX##_init_object_layout(void *data, int size, int max_aspects, const struct generic_object_type *object_type) \
|
|
|
|
{ \
|
|
|
|
struct PREFIX##_object_layout *object_layout = data; \
|
|
|
|
data += sizeof(struct PREFIX##_object_layout); \
|
|
|
|
size -= sizeof(struct PREFIX##_object_layout); \
|
|
|
|
if (size < 0) \
|
|
|
|
return NULL; \
|
|
|
|
object_layout->object_type = object_type; \
|
|
|
|
object_layout->object_size = object_type->default_size; \
|
|
|
|
object_layout->rest_size = size; \
|
|
|
|
object_layout->aspect_count = 0; \
|
|
|
|
return object_layout; \
|
|
|
|
} \
|
|
|
|
|
|
|
|
#define GENERIC_ASPECT_LAYOUT_FUNCTIONS(BRICK,PREFIX) \
|
|
|
|
\
|
|
|
|
extern inline int BRICK##_##PREFIX##_add_aspect(struct BRICK##_output *output, struct generic_object_layout *object_layout, const struct generic_aspect_type *aspect_type) \
|
|
|
|
{ \
|
|
|
|
int res = generic_add_aspect((struct generic_output*)output, object_layout, aspect_type); \
|
|
|
|
BRICK_DBG(#BRICK " " #PREFIX "added aspect_type %p (%s) to object_layout %p (type %s) on output %p (type %s), status=%d\n", aspect_type, aspect_type->aspect_type_name, object_layout, object_layout->object_type->object_type_name, output, output->type->type_name, res); \
|
|
|
|
return res; \
|
|
|
|
} \
|
|
|
|
|
|
|
|
#define GENERIC_OBJECT_FUNCTIONS(PREFIX) \
|
|
|
|
\
|
|
|
|
extern inline struct PREFIX##_object *PREFIX##_construct(void *data, struct PREFIX##_object_layout *object_layout) \
|
|
|
|
{ \
|
|
|
|
struct PREFIX##_object *obj = data; \
|
|
|
|
int i; \
|
|
|
|
\
|
|
|
|
obj->object_layout = object_layout; \
|
|
|
|
for (i = 0; i < object_layout->aspect_count; i++) { \
|
|
|
|
struct generic_aspect_layout *aspect_layout; \
|
|
|
|
struct generic_aspect *aspect; \
|
|
|
|
aspect_layout = object_layout->aspect_layouts[i]; \
|
|
|
|
if (!aspect_layout->aspect_type) \
|
|
|
|
continue; \
|
|
|
|
aspect = data + aspect_layout->aspect_offset; \
|
|
|
|
aspect->object = (void*)obj; \
|
|
|
|
if (aspect_layout->aspect_type->init_fn) { \
|
|
|
|
int status = aspect_layout->aspect_type->init_fn((void*)aspect, aspect_layout->init_data); \
|
|
|
|
if (status) { \
|
|
|
|
return NULL; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
return obj; \
|
|
|
|
} \
|
|
|
|
|
|
|
|
#define GENERIC_ASPECT_FUNCTIONS(BRICK,PREFIX) \
|
|
|
|
\
|
|
|
|
extern inline struct BRICK##_##PREFIX##_aspect *BRICK##_##PREFIX##_get_aspect(struct BRICK##_output *output, struct PREFIX##_object *obj) \
|
|
|
|
{ \
|
|
|
|
struct PREFIX##_object_layout *object_layout; \
|
|
|
|
struct generic_aspect_layout *aspect_layout; \
|
|
|
|
int nr; \
|
|
|
|
\
|
|
|
|
object_layout = obj->object_layout; \
|
|
|
|
nr = object_layout->object_type->brick_obj_nr; \
|
|
|
|
aspect_layout = &output->aspect_layouts[nr]; \
|
|
|
|
if (unlikely(!aspect_layout->aspect_type)) { \
|
|
|
|
BRICK_ERR("brick "#BRICK": bad aspect slot on "#PREFIX" pointer %p\n", obj); \
|
|
|
|
return NULL; \
|
|
|
|
} \
|
|
|
|
return (void*)obj + aspect_layout->aspect_offset; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// some helpers
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_SPINLOCK
|
2010-07-30 11:50:20 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
# define LOCK_CHECK(OP) \
|
|
|
|
({ \
|
|
|
|
if (atomic_read(¤t->lock_count)) { \
|
|
|
|
BRICK_ERR("never call " #OP "() with a spinlock held.\n"); \
|
|
|
|
} \
|
|
|
|
})
|
2010-07-30 11:50:20 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
# define traced_lock(spinlock,flags) \
|
|
|
|
do { \
|
|
|
|
if (atomic_read(¤t->lock_count)) { \
|
|
|
|
BRICK_ERR("please do not nest spinlocks at line %d, that's dangerous. reorganize your code!\n", __LINE__); \
|
|
|
|
} \
|
|
|
|
atomic_inc(¤t->lock_count); \
|
|
|
|
spin_lock_irqsave(spinlock,flags); \
|
|
|
|
} while (0)
|
2010-07-30 11:50:20 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
# define traced_unlock(spinlock,flags) \
|
|
|
|
do { \
|
|
|
|
spin_unlock_irqrestore(spinlock,flags); \
|
|
|
|
atomic_dec(¤t->lock_count); \
|
|
|
|
} while (0)
|
2010-07-30 11:50:20 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
#else
|
2010-07-30 11:50:20 +00:00
|
|
|
|
|
|
|
# define LOCK_CHECK(OP) 0
|
2010-07-30 05:46:22 +00:00
|
|
|
# define traced_lock(spinlock,flags) spin_lock_irqsave(spinlock,flags)
|
|
|
|
# define traced_unlock(spinlock,flags) spin_unlock_irqrestore(spinlock,flags)
|
2010-07-23 11:55:18 +00:00
|
|
|
|
|
|
|
#endif
|
2010-07-30 11:50:20 +00:00
|
|
|
#endif
|