2010-07-23 11:55:18 +00:00
|
|
|
// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/string.h>
|
2011-02-23 20:48:06 +00:00
|
|
|
#include <linux/semaphore.h>
|
2010-07-23 11:55:18 +00:00
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
//#define BRICK_DEBUGGING
|
2011-02-23 20:48:06 +00:00
|
|
|
|
2011-03-07 05:55:10 +00:00
|
|
|
//#define USE_FREELIST // use this, but improve freeing
|
2010-07-30 05:46:22 +00:00
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
#define _STRATEGY
|
2011-03-22 14:36:26 +00:00
|
|
|
#define BRICK_OBJ_MAX /*empty => leads to an open array */
|
2010-07-30 05:46:22 +00:00
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
#include "brick.h"
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
#define GFP_BRICK GFP_NOIO
|
|
|
|
|
2011-04-15 10:13:22 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// messaging
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_KERNEL
|
|
|
|
|
|
|
|
#include <linux/preempt.h>
|
|
|
|
#include <linux/hardirq.h>
|
|
|
|
|
|
|
|
static char say_buf[1024] = {};
|
|
|
|
static int say_index = 0;
|
|
|
|
|
|
|
|
void say_mark(void)
|
|
|
|
{
|
|
|
|
if (say_buf[0]) {
|
|
|
|
printk("# %s", say_buf);
|
|
|
|
say_buf[0] = '\0';
|
|
|
|
say_index = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(say_mark);
|
|
|
|
|
|
|
|
void say(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (preempt_count() & (PREEMPT_MASK | SOFTIRQ_MASK | HARDIRQ_MASK)) {
|
|
|
|
va_start(args, fmt);
|
|
|
|
say_index += vsnprintf(say_buf + say_index, sizeof(say_buf) - say_index, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
if (unlikely(say_index >= sizeof(say_buf))) {
|
|
|
|
say_index = sizeof(say_buf);
|
|
|
|
say_buf[say_index-1] = '\0';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
say_mark();
|
|
|
|
va_start(args, fmt);
|
|
|
|
vprintk(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(say);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// number management
|
|
|
|
|
|
|
|
static char *nr_table = NULL;
|
|
|
|
static int nr_max = 256;
|
|
|
|
|
|
|
|
int get_nr(void)
|
|
|
|
{
|
|
|
|
char *new;
|
|
|
|
int nr;
|
|
|
|
|
|
|
|
if (unlikely(!nr_table)) {
|
|
|
|
nr_table = kzalloc(nr_max, GFP_BRICK);
|
|
|
|
if (!nr_table) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
for (nr = 1; nr < nr_max; nr++) {
|
|
|
|
if (!nr_table[nr]) {
|
|
|
|
nr_table[nr] = 1;
|
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new = kzalloc(nr_max << 1, GFP_BRICK);
|
|
|
|
if (!new)
|
|
|
|
return 0;
|
|
|
|
memcpy(new, nr_table, nr_max);
|
|
|
|
kfree(nr_table);
|
|
|
|
nr_table = new;
|
|
|
|
nr_max <<= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(get_nr);
|
|
|
|
|
|
|
|
void put_nr(int nr)
|
|
|
|
{
|
|
|
|
if (likely(nr_table && nr > 0 && nr < nr_max)) {
|
|
|
|
nr_table[nr] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(put_nr);
|
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// object stuff
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// brick stuff
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
int brick_obj_max = 0;
|
|
|
|
EXPORT_SYMBOL_GPL(brick_obj_max);
|
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
static int nr_brick_types = 0;
|
|
|
|
static const struct generic_brick_type *brick_types[MAX_BRICK_TYPES] = {};
|
|
|
|
|
|
|
|
int generic_register_brick_type(const struct generic_brick_type *new_type)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int found = -1;
|
2010-07-30 05:46:22 +00:00
|
|
|
BRICK_DBG("generic_register_brick_type() name=%s\n", new_type->type_name);
|
2010-07-23 11:55:18 +00:00
|
|
|
for (i = 0; i < nr_brick_types; i++) {
|
|
|
|
if (!brick_types[i]) {
|
|
|
|
found = i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(brick_types[i]->type_name, new_type->type_name)) {
|
2011-02-23 20:48:06 +00:00
|
|
|
BRICK_DBG("bricktype %s is already registered.\n", new_type->type_name);
|
|
|
|
return 0;
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found < 0) {
|
|
|
|
if (nr_brick_types >= MAX_BRICK_TYPES) {
|
2010-07-30 05:46:22 +00:00
|
|
|
BRICK_ERR("sorry, cannot register bricktype %s.\n", new_type->type_name);
|
|
|
|
return -ENOMEM;
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
found = nr_brick_types++;
|
|
|
|
}
|
|
|
|
brick_types[found] = new_type;
|
|
|
|
BRICK_DBG("generic_register_brick_type() done.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(generic_register_brick_type);
|
|
|
|
|
|
|
|
int generic_unregister_brick_type(const struct generic_brick_type *old_type)
|
|
|
|
{
|
|
|
|
BRICK_DBG("generic_unregister_brick_type()\n");
|
|
|
|
return -1; // NYI
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(generic_unregister_brick_type);
|
|
|
|
|
|
|
|
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,
|
2011-02-23 20:48:06 +00:00
|
|
|
const char **names)
|
2010-07-23 11:55:18 +00:00
|
|
|
{
|
|
|
|
struct generic_brick *brick = data;
|
|
|
|
int status;
|
|
|
|
int i;
|
|
|
|
|
2011-02-23 20:48:06 +00:00
|
|
|
BRICK_DBG("brick_type = %s\n", brick_type->type_name);
|
|
|
|
if (unlikely(!data)) {
|
|
|
|
BRICK_ERR("invalid memory\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// call the generic constructors
|
2010-07-23 11:55:18 +00:00
|
|
|
|
2011-02-23 20:48:06 +00:00
|
|
|
status = generic_brick_init(brick_type, brick, names ? *names++ : NULL);
|
2010-07-23 11:55:18 +00:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
data += brick_type->brick_size;
|
|
|
|
size -= brick_type->brick_size;
|
2010-07-30 05:46:22 +00:00
|
|
|
if (size < 0) {
|
|
|
|
BRICK_ERR("Not enough MEMORY\n");
|
2010-07-23 11:55:18 +00:00
|
|
|
return -ENOMEM;
|
2010-07-30 05:46:22 +00:00
|
|
|
}
|
2010-07-23 11:55:18 +00:00
|
|
|
if (!input_types) {
|
|
|
|
BRICK_DBG("generic_brick_init_full: switch to default input_types\n");
|
|
|
|
input_types = brick_type->default_input_types;
|
|
|
|
names = brick_type->default_input_names;
|
2011-03-23 17:58:02 +00:00
|
|
|
if (unlikely(!input_types)) {
|
|
|
|
BRICK_ERR("no input types specified\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("generic_brick_init_full: input_types\n");
|
|
|
|
brick->inputs = data;
|
|
|
|
data += sizeof(void*) * brick_type->max_inputs;
|
|
|
|
size -= sizeof(void*) * brick_type->max_inputs;
|
|
|
|
if (size < 0) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
for (i = 0; i < brick_type->max_inputs; i++) {
|
|
|
|
struct generic_input *input = data;
|
|
|
|
const struct generic_input_type *type = *input_types++;
|
|
|
|
if (!type || type->input_size <= 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
BRICK_DBG("generic_brick_init_full: calling generic_input_init()\n");
|
|
|
|
status = generic_input_init(brick, i, type, input, (names && *names) ? *names++ : type->type_name);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
data += type->input_size;
|
|
|
|
size -= type->input_size;
|
|
|
|
if (size < 0)
|
2010-07-30 05:46:22 +00:00
|
|
|
return -ENOMEM;
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
if (!output_types) {
|
|
|
|
BRICK_DBG("generic_brick_init_full: switch to default output_types\n");
|
|
|
|
output_types = brick_type->default_output_types;
|
|
|
|
names = brick_type->default_output_names;
|
2011-03-23 17:58:02 +00:00
|
|
|
if (unlikely(!output_types)) {
|
|
|
|
BRICK_ERR("no output types specified\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("generic_brick_init_full: output_types\n");
|
|
|
|
brick->outputs = data;
|
|
|
|
data += sizeof(void*) * brick_type->max_outputs;
|
|
|
|
size -= sizeof(void*) * brick_type->max_outputs;
|
|
|
|
if (size < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < brick_type->max_outputs; i++) {
|
|
|
|
struct generic_output *output = data;
|
|
|
|
const struct generic_output_type *type = *output_types++;
|
|
|
|
if (!type || type->output_size <= 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
BRICK_DBG("generic_brick_init_full: calling generic_output_init()\n");
|
|
|
|
generic_output_init(brick, i, type, output, (names && *names) ? *names++ : type->type_name);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
data += type->output_size;
|
|
|
|
size -= type->output_size;
|
2010-07-23 11:55:18 +00:00
|
|
|
if (size < 0)
|
2010-08-05 08:36:36 +00:00
|
|
|
return -ENOMEM;
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// call the specific constructors
|
|
|
|
BRICK_DBG("generic_brick_init_full: call specific contructors.\n");
|
|
|
|
if (brick_type->brick_construct) {
|
|
|
|
BRICK_DBG("generic_brick_init_full: calling brick_construct()\n");
|
|
|
|
status = brick_type->brick_construct(brick);
|
2011-03-23 17:58:02 +00:00
|
|
|
if (status < 0)
|
2010-07-23 11:55:18 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
for (i = 0; i < brick_type->max_inputs; i++) {
|
|
|
|
struct generic_input *input = brick->inputs[i];
|
|
|
|
if (!input)
|
|
|
|
continue;
|
|
|
|
if (!input->type) {
|
|
|
|
BRICK_ERR("input has no associated type!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (input->type->input_construct) {
|
|
|
|
BRICK_DBG("generic_brick_init_full: calling input_construct()\n");
|
|
|
|
status = input->type->input_construct(input);
|
2011-03-23 17:58:02 +00:00
|
|
|
if (status < 0)
|
2010-07-23 11:55:18 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < brick_type->max_outputs; i++) {
|
|
|
|
struct generic_output *output = brick->outputs[i];
|
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
if (!output->type) {
|
|
|
|
BRICK_ERR("output has no associated type!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (output->type->output_construct) {
|
|
|
|
BRICK_DBG("generic_brick_init_full: calling output_construct()\n");
|
|
|
|
status = output->type->output_construct(output);
|
2011-03-23 17:58:02 +00:00
|
|
|
if (status < 0)
|
2010-07-23 11:55:18 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(generic_brick_init_full);
|
|
|
|
|
|
|
|
int generic_brick_exit_full(struct generic_brick *brick)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int status;
|
|
|
|
// first, check all outputs
|
2011-03-23 17:58:02 +00:00
|
|
|
for (i = 0; i < brick->type->max_outputs; i++) {
|
2010-07-23 11:55:18 +00:00
|
|
|
struct generic_output *output = brick->outputs[i];
|
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
if (!output->type) {
|
|
|
|
BRICK_ERR("output has no associated type!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (output->nr_connected) {
|
|
|
|
BRICK_DBG("output is connected!\n");
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ok, test succeeded. start destruction...
|
|
|
|
for (i = 0; i < brick->type->max_outputs; i++) {
|
|
|
|
struct generic_output *output = brick->outputs[i];
|
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
if (!output->type) {
|
|
|
|
BRICK_ERR("output has no associated type!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (output->type->output_destruct) {
|
|
|
|
BRICK_DBG("generic_brick_exit_full: calling output_destruct()\n");
|
|
|
|
status = output->type->output_destruct(output);
|
|
|
|
if (status)
|
|
|
|
return status;
|
2011-03-24 16:05:46 +00:00
|
|
|
_generic_output_exit(output);
|
2010-07-23 11:55:18 +00:00
|
|
|
brick->outputs[i] = NULL; // others may remain leftover
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < brick->type->max_inputs; i++) {
|
|
|
|
struct generic_input *input = brick->inputs[i];
|
|
|
|
if (!input)
|
|
|
|
continue;
|
|
|
|
if (!input->type) {
|
|
|
|
BRICK_ERR("input has no associated type!\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (input->type->input_destruct) {
|
|
|
|
BRICK_DBG("generic_brick_exit_full: calling input_destruct()\n");
|
|
|
|
status = input->type->input_destruct(input);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
brick->inputs[i] = NULL; // others may remain leftover
|
|
|
|
status = generic_disconnect(input);
|
|
|
|
if (status)
|
|
|
|
return status;
|
2011-03-24 16:05:46 +00:00
|
|
|
generic_input_exit(input);
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (brick->type->brick_destruct) {
|
|
|
|
BRICK_DBG("generic_brick_exit_full: calling brick_destruct()\n");
|
|
|
|
status = brick->type->brick_destruct(brick);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
generic_brick_exit(brick);
|
2010-07-23 11:55:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(generic_brick_exit_full);
|
|
|
|
|
2010-07-30 11:50:20 +00:00
|
|
|
int generic_brick_exit_recursively(struct generic_brick *brick, bool destroy_inputs)
|
2010-07-23 11:55:18 +00:00
|
|
|
{
|
|
|
|
int final_status = 0;
|
2010-07-30 11:50:20 +00:00
|
|
|
LIST_HEAD(tmp);
|
|
|
|
|
|
|
|
list_add(&brick->tmp_head, &tmp);
|
|
|
|
while (!list_empty(&tmp)) {
|
2010-07-23 11:55:18 +00:00
|
|
|
int i;
|
|
|
|
int status;
|
2010-07-30 11:50:20 +00:00
|
|
|
int postpone = 0;
|
|
|
|
brick = container_of(tmp.next, struct generic_brick, tmp_head);
|
|
|
|
list_del_init(&brick->tmp_head);
|
2011-03-23 17:58:02 +00:00
|
|
|
for (i = 0; i < brick->type->max_outputs; i++) {
|
2010-07-23 11:55:18 +00:00
|
|
|
struct generic_output *output = brick->outputs[i];
|
2010-07-30 11:50:20 +00:00
|
|
|
if (output && output->nr_connected) {
|
|
|
|
postpone += output->nr_connected;
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-23 17:58:02 +00:00
|
|
|
for (i = 0; i < brick->type->max_inputs; i++) {
|
2010-07-23 11:55:18 +00:00
|
|
|
struct generic_input *input = brick->inputs[i];
|
2010-07-30 11:50:20 +00:00
|
|
|
if (input && input->connect) {
|
2010-07-23 11:55:18 +00:00
|
|
|
struct generic_brick *other = input->connect->brick;
|
2010-07-30 11:50:20 +00:00
|
|
|
if (destroy_inputs) {
|
|
|
|
list_add(&other->tmp_head, &tmp);
|
|
|
|
postpone++;
|
|
|
|
} else {
|
|
|
|
}
|
2010-07-23 11:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
2010-07-30 11:50:20 +00:00
|
|
|
if (postpone) {
|
|
|
|
list_add_tail(&brick->tmp_head, &tmp);
|
|
|
|
continue;
|
|
|
|
}
|
2010-07-23 11:55:18 +00:00
|
|
|
status = generic_brick_exit_full(brick);
|
|
|
|
if (status)
|
|
|
|
final_status = status;
|
|
|
|
}
|
|
|
|
return final_status;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(generic_brick_exit_recursively);
|
|
|
|
|
2010-08-04 17:32:04 +00:00
|
|
|
int generic_add_aspect(struct generic_output *output, struct generic_object_layout *object_layout, const struct generic_aspect_type *aspect_type)
|
|
|
|
{
|
|
|
|
struct generic_aspect_layout *aspect_layout;
|
|
|
|
int nr;
|
2011-03-22 14:36:26 +00:00
|
|
|
int i;
|
2011-03-24 16:05:46 +00:00
|
|
|
int status;
|
2011-03-22 14:36:26 +00:00
|
|
|
|
|
|
|
(void)i;
|
2010-08-04 17:32:04 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
status = -EINVAL;
|
|
|
|
if (unlikely(!object_layout || !object_layout->object_type)) {
|
|
|
|
goto err;
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
if (NEW_ASPECTS) {
|
|
|
|
nr = output->output_index;
|
|
|
|
if (nr <= 0 || nr > nr_max) {
|
|
|
|
BRICK_ERR("oops, bad nr = %d\n", nr);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
aspect_layout = &object_layout->aspect_layouts[nr];
|
|
|
|
} else {
|
|
|
|
nr = object_layout->object_type->brick_obj_nr;
|
|
|
|
if (nr < 0 || nr >= brick_obj_max) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
aspect_layout = (void*)&output->output_aspect_layouts[nr];
|
2011-03-23 17:58:02 +00:00
|
|
|
}
|
2011-03-22 14:36:26 +00:00
|
|
|
if (aspect_layout->aspect_type && aspect_layout->aspect_layout_generation == object_layout->object_layout_generation) {
|
2010-08-04 17:32:04 +00:00
|
|
|
/* aspect_layout is already initialized.
|
|
|
|
* this is a kind of "dynamic programming".
|
|
|
|
* ensure consistency to last call.
|
|
|
|
*/
|
|
|
|
int min_offset;
|
|
|
|
BRICK_DBG("reusing aspect_type %s on object_layout %p\n", aspect_type->aspect_type_name, object_layout);
|
2011-03-24 16:05:46 +00:00
|
|
|
status = -EBADF;
|
2010-08-04 17:32:04 +00:00
|
|
|
if (unlikely(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);
|
2011-03-24 16:05:46 +00:00
|
|
|
goto done;
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
|
|
|
if (unlikely(aspect_layout->init_data != output)) {
|
|
|
|
BRICK_ERR("inconsistent output assigment (aspect_type=%s)\n", aspect_type->aspect_type_name);
|
2011-03-24 16:05:46 +00:00
|
|
|
goto done;
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
|
|
|
min_offset = aspect_layout->aspect_offset + aspect_type->aspect_size;
|
2011-03-24 16:05:46 +00:00
|
|
|
status = -ENOMEM;
|
2010-11-26 13:45:10 +00:00
|
|
|
if (unlikely(object_layout->object_size > min_offset)) {
|
2010-08-04 17:32:04 +00:00
|
|
|
BRICK_ERR("overlapping aspects %d > %d (aspect_type=%s)\n", object_layout->object_size, min_offset, aspect_type->aspect_type_name);
|
2011-03-24 16:05:46 +00:00
|
|
|
goto done;
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
|
|
|
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;
|
2011-03-22 14:36:26 +00:00
|
|
|
aspect_layout->aspect_layout_generation = object_layout->object_layout_generation;
|
2010-11-26 13:45:10 +00:00
|
|
|
BRICK_DBG("initializing aspect_type %s on object_layout %p, object_size=%d\n", aspect_type->aspect_type_name, object_layout, object_layout->object_size);
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
if (NEW_ASPECTS) {
|
|
|
|
if (object_layout->aspect_count <= nr) {
|
|
|
|
object_layout->aspect_count = nr + 1;
|
2011-03-22 14:36:26 +00:00
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
} else {
|
|
|
|
// find an empty slot
|
|
|
|
nr = -1;
|
|
|
|
if (nr < 0) {
|
|
|
|
nr = object_layout->aspect_count++;
|
|
|
|
status = -ENOMEM;
|
|
|
|
if (unlikely(nr >= object_layout->aspect_max)) {
|
|
|
|
BRICK_ERR("aspect overflow\n");
|
|
|
|
goto done;
|
|
|
|
}
|
2011-03-22 14:36:26 +00:00
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
object_layout->aspect_layouts_table[nr] = aspect_layout;
|
2011-03-22 14:36:26 +00:00
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
status = 0;
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (status < 0) { // invalidate the layout
|
|
|
|
object_layout->object_type = NULL;
|
|
|
|
}
|
|
|
|
err:
|
|
|
|
return status;
|
2010-08-04 17:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(generic_add_aspect);
|
|
|
|
|
2010-07-23 11:55:18 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// default implementations
|
|
|
|
|
2011-03-20 17:38:08 +00:00
|
|
|
int brick_layout_generation = 1;
|
|
|
|
EXPORT_SYMBOL_GPL(brick_layout_generation);
|
|
|
|
|
|
|
|
/* (Re-)Make an object layout
|
|
|
|
*/
|
2010-08-05 15:54:48 +00:00
|
|
|
int default_init_object_layout(struct generic_output *output, struct generic_object_layout *object_layout, int aspect_max, const struct generic_object_type *object_type, char *module_name)
|
2010-08-01 20:21:18 +00:00
|
|
|
{
|
2010-08-05 08:36:36 +00:00
|
|
|
// TODO: make locking granularity finer (if it were worth).
|
|
|
|
static DEFINE_SPINLOCK(global_lock);
|
2010-08-01 20:21:18 +00:00
|
|
|
void *data;
|
2011-03-24 16:05:46 +00:00
|
|
|
void *data2;
|
2011-03-20 17:38:08 +00:00
|
|
|
void *olddata;
|
2011-03-24 16:05:46 +00:00
|
|
|
void *olddata2;
|
2010-08-05 08:36:36 +00:00
|
|
|
int status= -ENOMEM;
|
|
|
|
unsigned long flags;
|
2010-08-01 20:21:18 +00:00
|
|
|
|
2010-08-05 15:54:48 +00:00
|
|
|
if (unlikely(!module_name)) {
|
|
|
|
module_name = "(unknown)";
|
|
|
|
}
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
if (NEW_ASPECTS) {
|
|
|
|
aspect_max = nr_max;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = kzalloc(aspect_max * sizeof(struct generic_aspect_layout), GFP_BRICK);
|
|
|
|
data2 = kzalloc(aspect_max * sizeof(void*), GFP_BRICK);
|
|
|
|
if (unlikely(!data || !data2)) {
|
2011-03-22 14:36:26 +00:00
|
|
|
BRICK_ERR("kzalloc failed, size = %lu\n", aspect_max * sizeof(void*));
|
2010-08-05 08:36:36 +00:00
|
|
|
goto done;
|
2011-03-22 14:36:26 +00:00
|
|
|
}
|
2010-08-05 08:36:36 +00:00
|
|
|
|
|
|
|
traced_lock(&global_lock, flags);
|
|
|
|
|
2011-03-22 14:36:26 +00:00
|
|
|
if (unlikely(object_layout->object_type && object_layout->object_layout_generation == brick_layout_generation)) {
|
2010-08-05 08:36:36 +00:00
|
|
|
traced_unlock(&global_lock, flags);
|
2011-03-20 17:38:08 +00:00
|
|
|
BRICK_DBG("lost the race on object_layout %p/%s (no harm)\n", object_layout, module_name);
|
2010-08-05 08:36:36 +00:00
|
|
|
status = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
olddata = object_layout->aspect_layouts;
|
|
|
|
olddata2 = object_layout->aspect_layouts_table;
|
2011-03-20 17:38:08 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
object_layout->aspect_layouts_table = data2;
|
|
|
|
object_layout->aspect_layouts = data;
|
2011-03-22 14:36:26 +00:00
|
|
|
object_layout->object_layout_generation = brick_layout_generation;
|
2010-08-01 20:21:18 +00:00
|
|
|
object_layout->object_type = object_type;
|
2010-08-08 09:03:42 +00:00
|
|
|
object_layout->init_data = output;
|
2010-08-01 20:21:18 +00:00
|
|
|
object_layout->aspect_count = 0;
|
|
|
|
object_layout->aspect_max = aspect_max;
|
|
|
|
object_layout->object_size = object_type->default_size;
|
2010-08-05 15:54:48 +00:00
|
|
|
atomic_set(&object_layout->alloc_count, 0);
|
2010-08-08 09:03:42 +00:00
|
|
|
atomic_set(&object_layout->free_count, 0);
|
|
|
|
spin_lock_init(&object_layout->free_lock);
|
|
|
|
object_layout->free_list = NULL;
|
2010-08-05 15:54:48 +00:00
|
|
|
object_layout->module_name = module_name;
|
2010-08-01 20:21:18 +00:00
|
|
|
|
|
|
|
status = output->ops->make_object_layout(output, object_layout);
|
2010-08-05 08:36:36 +00:00
|
|
|
|
2010-08-01 20:21:18 +00:00
|
|
|
if (unlikely(status < 0)) {
|
2010-08-05 08:36:36 +00:00
|
|
|
object_layout->object_type = NULL;
|
2011-03-24 16:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
traced_unlock(&global_lock, flags);
|
|
|
|
|
|
|
|
if (unlikely(status < 0)) {
|
2010-08-01 20:21:18 +00:00
|
|
|
kfree(data);
|
2010-08-05 15:54:48 +00:00
|
|
|
BRICK_ERR("emergency, cannot add aspects to object_layout %s (module %s)\n", object_type->object_type_name, module_name);
|
2010-08-01 20:21:18 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2011-03-24 16:05:46 +00:00
|
|
|
|
2010-08-05 08:36:36 +00:00
|
|
|
|
2010-11-26 13:45:10 +00:00
|
|
|
BRICK_INF("OK, object_layout %s init succeeded (size = %d).\n", object_type->object_type_name, object_layout->object_size);
|
|
|
|
|
2010-08-01 20:21:18 +00:00
|
|
|
done:
|
2011-03-22 14:36:26 +00:00
|
|
|
if (olddata) {
|
|
|
|
#if 0 // FIXME: use RCU here
|
|
|
|
kfree(olddata);
|
2011-03-24 16:05:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (olddata2) {
|
|
|
|
#if 0 // FIXME: use RCU here
|
|
|
|
kfree(olddata2);
|
2011-03-22 14:36:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
2010-08-01 20:21:18 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(default_init_object_layout);
|
|
|
|
|
2011-03-20 17:38:08 +00:00
|
|
|
/* Callback, usually called for each brick instance.
|
|
|
|
* Initialize the information for single aspect associated to a single brick.
|
|
|
|
*/
|
2010-07-23 11:55:18 +00:00
|
|
|
int default_make_object_layout(struct generic_output *output, struct generic_object_layout *object_layout)
|
|
|
|
{
|
2011-03-24 16:05:46 +00:00
|
|
|
struct generic_brick *brick;
|
|
|
|
const struct generic_output_type *output_type;
|
|
|
|
const struct generic_object_type *object_type;
|
|
|
|
const struct generic_aspect_type *aspect_type;
|
|
|
|
int nr;
|
|
|
|
int layout_code;
|
|
|
|
int aspect_size = 0;
|
|
|
|
int status = -EINVAL;
|
2010-07-23 11:55:18 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
if (unlikely(!output)) {
|
|
|
|
BRICK_ERR("output is missing\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (unlikely(!object_layout || !object_layout->object_type)) {
|
|
|
|
BRICK_ERR("object_layout not inizialized\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
brick = output->brick;
|
|
|
|
if (unlikely(!brick)) {
|
|
|
|
BRICK_ERR("brick is missing\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
output_type = output->type;
|
|
|
|
if (unlikely(!output_type)) {
|
|
|
|
BRICK_ERR("output_type is missing\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
object_type = object_layout->object_type;
|
|
|
|
if (unlikely(!object_type)) {
|
|
|
|
BRICK_ERR("object_type is missing\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
nr = object_type->brick_obj_nr;
|
|
|
|
if (unlikely(nr < 0 || nr >= brick_obj_max)) {
|
|
|
|
BRICK_ERR("bad brick_obj_nr = %d\n", nr);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
layout_code = output_type->layout_code[nr];
|
|
|
|
aspect_type = output_type->aspect_types[nr];
|
|
|
|
status = -ENOENT;
|
|
|
|
if (unlikely(!aspect_type)) {
|
2010-07-30 05:46:22 +00:00
|
|
|
BRICK_ERR("aspect type on %s does not exist\n", output_type->type_name);
|
2011-03-24 16:05:46 +00:00
|
|
|
goto done;
|
2010-07-30 05:46:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aspect_size = aspect_type->aspect_size;
|
|
|
|
|
|
|
|
if (layout_code == LAYOUT_ALL) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < brick->type->max_inputs; i++) {
|
|
|
|
struct generic_input *input = brick->inputs[i];
|
|
|
|
if (input && input->connect) {
|
|
|
|
int substatus = input->connect->ops->make_object_layout(input->connect, object_layout);
|
|
|
|
if (substatus < 0)
|
|
|
|
return substatus;
|
|
|
|
aspect_size += substatus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (; layout_code != 0; layout_code >>= 8) {
|
|
|
|
unsigned int my_code = layout_code & 255;
|
|
|
|
struct generic_input *input;
|
|
|
|
int substatus;
|
|
|
|
if (my_code == 255)
|
|
|
|
break;
|
|
|
|
if (my_code >= brick->type->max_inputs)
|
|
|
|
continue;
|
|
|
|
input = brick->inputs[my_code];
|
|
|
|
if (!input || !input->connect)
|
|
|
|
continue;
|
|
|
|
substatus = input->connect->ops->make_object_layout(input->connect, object_layout);
|
2010-07-23 11:55:18 +00:00
|
|
|
if (substatus < 0)
|
|
|
|
return substatus;
|
|
|
|
aspect_size += substatus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-30 05:46:22 +00:00
|
|
|
|
|
|
|
status = generic_add_aspect(output, object_layout, aspect_type);
|
2010-07-23 11:55:18 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
done:
|
2010-07-23 11:55:18 +00:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return aspect_size;
|
|
|
|
}
|
2010-07-30 05:46:22 +00:00
|
|
|
EXPORT_SYMBOL_GPL(default_make_object_layout);
|
|
|
|
|
2010-08-04 17:32:04 +00:00
|
|
|
|
|
|
|
struct generic_object *alloc_generic(struct generic_object_layout *object_layout)
|
2010-08-01 20:21:18 +00:00
|
|
|
{
|
2011-03-24 16:05:46 +00:00
|
|
|
struct generic_object *object;
|
2010-08-01 20:21:18 +00:00
|
|
|
void *data;
|
2010-08-08 09:03:42 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
if (unlikely(!object_layout || !object_layout->object_type)) {
|
|
|
|
BRICK_ERR("bad object_layout\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
object = object_layout->free_list;
|
2010-08-08 09:03:42 +00:00
|
|
|
if (object) {
|
|
|
|
unsigned long flags;
|
|
|
|
traced_lock(&object_layout->free_lock, flags);
|
|
|
|
object = object_layout->free_list;
|
|
|
|
if (object) {
|
|
|
|
object_layout->free_list = *(struct generic_object**)object;
|
|
|
|
*(struct generic_object**)object = NULL;
|
|
|
|
traced_unlock(&object_layout->free_lock, flags);
|
|
|
|
atomic_dec(&object_layout->free_count);
|
|
|
|
data = object;
|
|
|
|
goto ok;
|
|
|
|
}
|
|
|
|
traced_unlock(&object_layout->free_lock, flags);
|
|
|
|
}
|
2010-08-01 20:21:18 +00:00
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
data = kzalloc(object_layout->object_size, GFP_BRICK);
|
2010-08-01 20:21:18 +00:00
|
|
|
if (unlikely(!data))
|
|
|
|
goto err;
|
|
|
|
|
2010-08-08 09:03:42 +00:00
|
|
|
atomic_inc(&object_layout->alloc_count);
|
|
|
|
|
|
|
|
ok:
|
2010-08-01 20:21:18 +00:00
|
|
|
object = generic_construct(data, object_layout);
|
|
|
|
if (unlikely(!object))
|
|
|
|
goto err_free;
|
|
|
|
|
2010-08-05 15:54:48 +00:00
|
|
|
#if 1
|
|
|
|
{
|
|
|
|
int count = atomic_read(&object_layout->alloc_count);
|
2010-11-26 13:45:10 +00:00
|
|
|
if (count >= object_layout->last_count + 1000 || ((int)jiffies - object_layout->last_jiffies) >= 30 * HZ) {
|
2010-08-05 15:54:48 +00:00
|
|
|
object_layout->last_count = count;
|
2010-11-26 13:45:10 +00:00
|
|
|
object_layout->last_jiffies = jiffies;
|
2010-08-08 09:03:42 +00:00
|
|
|
BRICK_INF("pool %s/%p/%s alloc=%d free=%d\n", object_layout->object_type->object_type_name, object_layout, object_layout->module_name, count, atomic_read(&object_layout->free_count));
|
2010-08-05 15:54:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-08-01 20:21:18 +00:00
|
|
|
return object;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
kfree(data);
|
|
|
|
err:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(alloc_generic);
|
2010-08-02 16:31:10 +00:00
|
|
|
|
|
|
|
void free_generic(struct generic_object *object)
|
|
|
|
{
|
2010-08-08 09:03:42 +00:00
|
|
|
struct generic_object_layout *object_layout;
|
2010-08-05 15:54:48 +00:00
|
|
|
if (unlikely(!object)) {
|
|
|
|
BRICK_ERR("free_generic on NULL object\n");
|
|
|
|
return;
|
|
|
|
}
|
2010-08-08 09:03:42 +00:00
|
|
|
object_layout = object->object_layout;
|
|
|
|
if (likely(object_layout)) {
|
|
|
|
generic_destruct(object);
|
|
|
|
|
|
|
|
#ifdef USE_FREELIST
|
|
|
|
memset(object, 0, object_layout->object_size);
|
|
|
|
atomic_inc(&object_layout->free_count);
|
|
|
|
|
2011-03-07 18:36:08 +00:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
2010-08-08 09:03:42 +00:00
|
|
|
|
2011-03-07 18:36:08 +00:00
|
|
|
traced_lock(&object_layout->free_lock, flags);
|
2010-08-08 09:03:42 +00:00
|
|
|
|
2011-03-07 18:36:08 +00:00
|
|
|
*(struct generic_object**)object = object_layout->free_list;
|
|
|
|
object_layout->free_list = object;
|
|
|
|
|
|
|
|
traced_unlock(&object_layout->free_lock, flags);
|
|
|
|
}
|
2010-08-08 09:03:42 +00:00
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
atomic_dec(&object_layout->alloc_count);
|
|
|
|
}
|
2010-08-05 15:54:48 +00:00
|
|
|
|
2010-08-02 16:31:10 +00:00
|
|
|
kfree(object);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(free_generic);
|
2010-08-06 11:29:06 +00:00
|
|
|
|
2011-02-23 20:48:06 +00:00
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// helper stuff
|
|
|
|
|
|
|
|
struct semaphore lamport_sem = __SEMAPHORE_INITIALIZER(lamport_sem, 1); // TODO: replace with spinlock if possible (first check)
|
|
|
|
struct timespec lamport_now = {};
|
|
|
|
|
|
|
|
void get_lamport(struct timespec *now)
|
|
|
|
{
|
|
|
|
int diff;
|
|
|
|
|
|
|
|
down(&lamport_sem);
|
|
|
|
|
2011-03-29 14:40:40 +00:00
|
|
|
//*now = current_kernel_time();
|
2011-02-23 20:48:06 +00:00
|
|
|
*now = CURRENT_TIME;
|
|
|
|
diff = timespec_compare(now, &lamport_now);
|
|
|
|
if (diff > 0) {
|
|
|
|
memcpy(&lamport_now, now, sizeof(lamport_now));
|
|
|
|
} else {
|
|
|
|
timespec_add_ns(&lamport_now, 1);
|
|
|
|
memcpy(now, &lamport_now, sizeof(*now));
|
|
|
|
}
|
|
|
|
|
|
|
|
up(&lamport_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(get_lamport);
|
|
|
|
|
|
|
|
void set_lamport(struct timespec *old)
|
|
|
|
{
|
|
|
|
int diff;
|
|
|
|
|
|
|
|
down(&lamport_sem);
|
|
|
|
|
|
|
|
diff = timespec_compare(old, &lamport_now);
|
|
|
|
if (diff > 0) {
|
|
|
|
memcpy(&lamport_now, old, sizeof(lamport_now));
|
|
|
|
}
|
|
|
|
|
|
|
|
up(&lamport_sem);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_lamport);
|
|
|
|
|
2011-02-27 14:17:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
void set_button(struct generic_switch *sw, bool val, bool force)
|
2011-02-23 20:48:06 +00:00
|
|
|
{
|
|
|
|
bool oldval = sw->button;
|
2011-02-27 14:17:58 +00:00
|
|
|
if ((sw->force_off |= force))
|
|
|
|
val = false;
|
2011-02-23 20:48:06 +00:00
|
|
|
if (val != oldval) {
|
|
|
|
sw->button = val;
|
2011-02-27 14:17:58 +00:00
|
|
|
//sw->trigger = true;
|
2011-02-23 20:48:06 +00:00
|
|
|
wake_up_interruptible(&sw->event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_button);
|
|
|
|
|
|
|
|
void set_led_on(struct generic_switch *sw, bool val)
|
|
|
|
{
|
|
|
|
bool oldval = sw->led_on;
|
|
|
|
if (val != oldval) {
|
|
|
|
sw->led_on = val;
|
2011-02-27 14:17:58 +00:00
|
|
|
//sw->trigger = true;
|
2011-02-23 20:48:06 +00:00
|
|
|
wake_up_interruptible(&sw->event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_led_on);
|
|
|
|
|
|
|
|
void set_led_off(struct generic_switch *sw, bool val)
|
|
|
|
{
|
|
|
|
bool oldval = sw->led_off;
|
|
|
|
if (val != oldval) {
|
|
|
|
sw->led_off = val;
|
2011-02-27 14:17:58 +00:00
|
|
|
//sw->trigger = true;
|
2011-02-23 20:48:06 +00:00
|
|
|
wake_up_interruptible(&sw->event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_led_off);
|
|
|
|
|
2011-03-01 09:34:36 +00:00
|
|
|
void set_button_wait(struct generic_brick *brick, bool val, bool force, int timeout)
|
2011-02-27 14:17:58 +00:00
|
|
|
{
|
2011-03-01 09:34:36 +00:00
|
|
|
set_button(&brick->power, val, force);
|
|
|
|
if (brick->ops)
|
|
|
|
(void)brick->ops->brick_switch(brick);
|
2011-02-27 14:17:58 +00:00
|
|
|
if (val) {
|
2011-03-01 09:34:36 +00:00
|
|
|
wait_event_interruptible_timeout(brick->power.event, brick->power.led_on, timeout);
|
2011-02-27 14:17:58 +00:00
|
|
|
} else {
|
2011-03-01 09:34:36 +00:00
|
|
|
wait_event_interruptible_timeout(brick->power.event, brick->power.led_off, timeout);
|
2011-02-27 14:17:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_button_wait);
|
|
|
|
|
2011-03-01 18:00:14 +00:00
|
|
|
/* Do it iteratively behind the scenes ;)
|
|
|
|
*/
|
2011-02-28 18:00:32 +00:00
|
|
|
int set_recursive_button(struct generic_brick *orig_brick, brick_switch_t mode, int timeout)
|
2011-02-27 14:17:58 +00:00
|
|
|
{
|
|
|
|
struct generic_brick **table = NULL;
|
|
|
|
int max = PAGE_SIZE / sizeof(void*) / 2;
|
|
|
|
int stack;
|
2011-02-28 18:00:32 +00:00
|
|
|
bool val = (mode == BR_ON_ONE || mode == BR_ON_ALL);
|
|
|
|
bool force = (mode != BR_OFF_ONE && mode != BR_OFF_ALL);
|
2011-03-23 17:58:02 +00:00
|
|
|
int pos;
|
2011-02-27 14:17:58 +00:00
|
|
|
int status;
|
|
|
|
|
2011-03-01 18:00:14 +00:00
|
|
|
#define PUSH_STACK(next) \
|
|
|
|
{ \
|
|
|
|
int j; \
|
|
|
|
bool found = false; \
|
2011-03-23 17:58:02 +00:00
|
|
|
/* eliminate duplicates */ \
|
2011-03-01 18:00:14 +00:00
|
|
|
for (j = 0; j < stack; j++) { \
|
2011-03-23 17:58:02 +00:00
|
|
|
if (table[j] == (next)) { \
|
|
|
|
BRICK_DBG(" double entry %d '%s' stack = %d\n", i, (next)->brick_name, stack); \
|
2011-03-01 18:00:14 +00:00
|
|
|
found = true; \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
if (!found) { \
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG(" push '%s' stack = %d\n", (next)->brick_name, stack); \
|
|
|
|
table[stack++] = (next); \
|
2011-03-01 18:00:14 +00:00
|
|
|
if (unlikely(stack > max)) { \
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_ERR("---- max = %d overflow, restarting...\n", max); \
|
2011-03-01 18:00:14 +00:00
|
|
|
goto restart; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2011-02-27 14:17:58 +00:00
|
|
|
restart:
|
2011-03-01 09:34:36 +00:00
|
|
|
BRICK_DBG("-> orig_brick = '%s'\n", orig_brick->brick_name);
|
2011-02-27 14:17:58 +00:00
|
|
|
if (table)
|
|
|
|
kfree(table);
|
|
|
|
max <<= 1;
|
2011-03-24 16:05:46 +00:00
|
|
|
table = kmalloc(max * sizeof(void*), GFP_BRICK);
|
2011-02-27 14:17:58 +00:00
|
|
|
status = -ENOMEM;
|
|
|
|
if (unlikely(!table))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
stack = 0;
|
|
|
|
table[stack++] = orig_brick;
|
|
|
|
|
|
|
|
status = -EAGAIN;
|
2011-03-23 17:58:02 +00:00
|
|
|
for (pos = 0; pos < stack; pos++) {
|
|
|
|
struct generic_brick *brick = table[pos];
|
2011-03-01 18:00:14 +00:00
|
|
|
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("--> pos = %d stack = %d brick = '%s' inputs = %d/%d outputs = %d/%d\n", pos, stack, brick->brick_name, brick->nr_inputs, brick->type->max_inputs, brick->nr_outputs, brick->type->max_outputs);
|
2011-02-27 14:17:58 +00:00
|
|
|
|
|
|
|
if (val) {
|
|
|
|
force = false;
|
|
|
|
if (unlikely(brick->power.force_off)) {
|
|
|
|
status = -EDEADLK;
|
|
|
|
goto done;
|
|
|
|
}
|
2011-02-28 18:00:32 +00:00
|
|
|
if (mode >= BR_ON_ALL) {
|
2011-03-23 17:58:02 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < brick->type->max_inputs; i++) {
|
2011-02-28 18:00:32 +00:00
|
|
|
struct generic_input *input = brick->inputs[i];
|
|
|
|
struct generic_output *output;
|
|
|
|
struct generic_brick *next;
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("---> i = %d\n", i);
|
2011-03-24 16:05:46 +00:00
|
|
|
//msleep(1000);
|
2011-02-28 18:00:32 +00:00
|
|
|
if (!input)
|
|
|
|
continue;
|
|
|
|
output = input->connect;
|
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
next = output->brick;
|
|
|
|
if (!next)
|
|
|
|
continue;
|
2011-03-01 18:00:14 +00:00
|
|
|
|
|
|
|
PUSH_STACK(next);
|
2011-02-27 14:17:58 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-28 18:00:32 +00:00
|
|
|
} else if (mode >= BR_ON_ALL) {
|
2011-03-23 17:58:02 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < brick->type->max_outputs; i++) {
|
2011-02-27 14:17:58 +00:00
|
|
|
struct generic_output *output = brick->outputs[i];
|
|
|
|
struct list_head *tmp;
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("---> i = %d output = %p\n", i, output);
|
2011-03-24 16:05:46 +00:00
|
|
|
//msleep(1000);
|
2011-02-27 14:17:58 +00:00
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
for (tmp = output->output_head.next; tmp && tmp != &output->output_head; tmp = tmp->next) {
|
2011-03-23 17:58:02 +00:00
|
|
|
struct generic_input *input = container_of(tmp, struct generic_input, input_head);
|
|
|
|
struct generic_brick *next = input->brick;
|
|
|
|
BRICK_DBG("----> tmp = %p input = %p next = %p\n", tmp, input, next);
|
2011-03-24 16:05:46 +00:00
|
|
|
//msleep(1000);
|
2011-03-23 17:58:02 +00:00
|
|
|
if (unlikely(!next)) {
|
|
|
|
BRICK_ERR("oops, bad brick pointer\n");
|
|
|
|
status = -EINVAL;
|
|
|
|
goto done;
|
|
|
|
}
|
2011-03-01 18:00:14 +00:00
|
|
|
PUSH_STACK(next);
|
2011-02-27 14:17:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-01 18:00:14 +00:00
|
|
|
}
|
2011-02-27 14:17:58 +00:00
|
|
|
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("-> stack = %d\n", stack);
|
|
|
|
|
2011-03-01 18:00:14 +00:00
|
|
|
while (stack > 0) {
|
|
|
|
struct generic_brick *brick = table[--stack];
|
2011-03-01 09:34:36 +00:00
|
|
|
BRICK_DBG("--> switch '%s' stack = %d\n", brick->brick_name, stack);
|
|
|
|
set_button_wait(brick, val, force, timeout);
|
2011-02-27 14:17:58 +00:00
|
|
|
if (val ? !brick->power.led_on : !brick->power.led_off) {
|
|
|
|
BRICK_DBG("switching to %d: brick '%s' not ready (%s)\n", val, brick->brick_name, orig_brick->brick_name);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-02-28 18:00:32 +00:00
|
|
|
if (force && !val && (mode == BR_FREE_ONE || mode == BR_FREE_ALL) && brick->free) {
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("---> freeing '%s'\n", brick->brick_name);
|
2011-02-28 18:00:32 +00:00
|
|
|
status = brick->free(brick);
|
2011-03-23 17:58:02 +00:00
|
|
|
BRICK_DBG("---> freeing '%s' status = %d\n", brick->brick_name, status);
|
2011-02-28 18:00:32 +00:00
|
|
|
if (status < 0) {
|
|
|
|
BRICK_DBG("freeing brick '%s' (%s) failed, status = %d\n", brick->brick_name, orig_brick->brick_name, status);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-27 14:17:58 +00:00
|
|
|
}
|
|
|
|
status = 0;
|
|
|
|
|
2011-03-23 17:58:02 +00:00
|
|
|
done:
|
|
|
|
BRICK_DBG("-> done '%s' status = %d\n", orig_brick->brick_name, status);
|
2011-02-27 14:17:58 +00:00
|
|
|
if (table)
|
|
|
|
kfree(table);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(set_recursive_button);
|
|
|
|
|
2011-02-23 20:48:06 +00:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// meta stuff
|
|
|
|
|
|
|
|
const struct meta *find_meta(const struct meta *meta, const char *field_name)
|
|
|
|
{
|
|
|
|
const struct meta *tmp;
|
|
|
|
for (tmp = meta; tmp->field_name[0]; tmp++) {
|
|
|
|
if (!strncmp(field_name, tmp->field_name, MAX_FIELD_LEN)) {
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(find_meta);
|
|
|
|
|
|
|
|
void free_meta(void *data, const struct meta *meta)
|
|
|
|
{
|
|
|
|
for (; meta->field_name[0]; meta++) {
|
|
|
|
void *item;
|
|
|
|
switch (meta->field_type) {
|
|
|
|
case FIELD_SUB:
|
|
|
|
if (meta->field_ref) {
|
|
|
|
item = data + meta->field_offset;
|
|
|
|
free_meta(item, meta->field_ref);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FIELD_REF:
|
|
|
|
case FIELD_STRING:
|
|
|
|
item = data + meta->field_offset;
|
|
|
|
item = *(void**)item;
|
|
|
|
if (meta->field_ref)
|
|
|
|
free_meta(item, meta->field_ref);
|
|
|
|
kfree(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(free_meta);
|
|
|
|
|
2011-03-24 16:05:46 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// module init stuff
|
|
|
|
|
|
|
|
static int __init init_brick(void)
|
|
|
|
{
|
|
|
|
nr_table = kzalloc(nr_max, GFP_BRICK);
|
|
|
|
if (!nr_table) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit exit_brick(void)
|
|
|
|
{
|
|
|
|
if (nr_table) {
|
|
|
|
kfree(nr_table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_DESCRIPTION("generic brick infrastructure");
|
|
|
|
MODULE_AUTHOR("Thomas Schoebel-Theuer <tst@1und1.de>");
|
2010-08-06 11:29:06 +00:00
|
|
|
MODULE_LICENSE("GPL");
|
2011-03-24 16:05:46 +00:00
|
|
|
|
|
|
|
module_init(init_brick);
|
|
|
|
module_exit(exit_brick);
|