1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-03-21 00:38:52 +02:00
blogic 6ea7ec75d2 [ifxmips]
* adds a rewrite of the tapi drivers + sip app. this is the result of lars' gsoc 2010 project, Thanks !


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23840 3c298f89-4303-0410-b956-a3cf2f4a3e73
2010-11-03 19:12:34 +00:00

131 lines
2.8 KiB
C

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <asm/bitops.h>
#include "vmmc-module.h"
int vmmc_module_init(struct vmmc_module *module, size_t num_pins,
const struct vmmc_module_ops *ops)
{
module->pins = kcalloc(num_pins, sizeof(*module->pins), GFP_KERNEL);
if (!module->pins)
return -ENOMEM;
module->num_pins = num_pins;
module->ops = ops;
mutex_init(&module->lock);
module->refcount = 0;
return 0;
}
int vmmc_module_sync(struct vmmc_module *module)
{
if (!test_and_clear_bit(VMMC_MODULE_FLAG_MODIFIED, &module->flags))
return 0;
return module->ops->sync(module);
}
int vmmc_module_get_pin(struct vmmc_module *module)
{
size_t i = 0;
int ret = 0;
for (i = 0; i < module->num_pins; ++i) {
if (!test_and_set_bit(VMMC_MODULE_FLAG_PIN_USED(i), &module->flags))
break;
}
if (i == module->num_pins)
ret = -EBUSY;
else
ret = i;
return ret;
}
void vmmc_module_put_pin(struct vmmc_module *module, unsigned int pin)
{
module->pins[pin] = 0;
clear_bit(VMMC_MODULE_FLAG_PIN_USED(pin), &module->flags);
}
void vmmc_module_set_pin_input(struct vmmc_module *module, unsigned int pin,
struct vmmc_module *input)
{
if (input)
module->pins[pin] = input->id;
else
module->pins[pin] = 0;
set_bit(VMMC_MODULE_FLAG_MODIFIED, &module->flags);
}
static void vmmc_module_enable(struct vmmc_module *module)
{
mutex_lock(&module->lock);
if (++module->refcount == 1)
module->ops->enable(module, true);
mutex_unlock(&module->lock);
}
static void vmmc_module_disable(struct vmmc_module *module)
{
mutex_lock(&module->lock);
if (module->refcount <= 0)
printk(KERN_ERR "vmmc module: unbalanced disable\n");
else if (--module->refcount == 0)
module->ops->enable(module, false);
mutex_unlock(&module->lock);
}
unsigned int vmmc_link_init(struct vmmc_link *link,
struct vmmc_module *a, struct vmmc_module *b)
{
link->pins[0] = vmmc_module_get_pin(a);
link->pins[1] = vmmc_module_get_pin(b);
link->modules[0] = a;
link->modules[1] = b;
return 0;
}
void vmmc_link_put(struct vmmc_link *link)
{
vmmc_link_disable(link);
vmmc_module_sync(link->modules[0]);
vmmc_module_sync(link->modules[1]);
vmmc_module_put_pin(link->modules[0], link->pins[0]);
vmmc_module_put_pin(link->modules[1], link->pins[1]);
}
void vmmc_link_enable(struct vmmc_link *link)
{
vmmc_module_set_pin_input(link->modules[0], link->pins[0],
link->modules[1]);
vmmc_module_set_pin_input(link->modules[1], link->pins[1],
link->modules[0]);
vmmc_module_enable(link->modules[0]);
vmmc_module_enable(link->modules[1]);
}
void vmmc_link_disable(struct vmmc_link *link)
{
vmmc_module_set_pin_input(link->modules[0], link->pins[0], NULL);
vmmc_module_set_pin_input(link->modules[1], link->pins[1], NULL);
vmmc_module_disable(link->modules[0]);
vmmc_module_disable(link->modules[1]);
}