#include #include #include #include #include #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]); }