0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/irqbypass.h>
0018 #include <linux/list.h>
0019 #include <linux/module.h>
0020 #include <linux/mutex.h>
0021
0022 MODULE_LICENSE("GPL v2");
0023 MODULE_DESCRIPTION("IRQ bypass manager utility module");
0024
0025 static LIST_HEAD(producers);
0026 static LIST_HEAD(consumers);
0027 static DEFINE_MUTEX(lock);
0028
0029
0030 static int __connect(struct irq_bypass_producer *prod,
0031 struct irq_bypass_consumer *cons)
0032 {
0033 int ret = 0;
0034
0035 if (prod->stop)
0036 prod->stop(prod);
0037 if (cons->stop)
0038 cons->stop(cons);
0039
0040 if (prod->add_consumer)
0041 ret = prod->add_consumer(prod, cons);
0042
0043 if (!ret) {
0044 ret = cons->add_producer(cons, prod);
0045 if (ret && prod->del_consumer)
0046 prod->del_consumer(prod, cons);
0047 }
0048
0049 if (cons->start)
0050 cons->start(cons);
0051 if (prod->start)
0052 prod->start(prod);
0053
0054 return ret;
0055 }
0056
0057
0058 static void __disconnect(struct irq_bypass_producer *prod,
0059 struct irq_bypass_consumer *cons)
0060 {
0061 if (prod->stop)
0062 prod->stop(prod);
0063 if (cons->stop)
0064 cons->stop(cons);
0065
0066 cons->del_producer(cons, prod);
0067
0068 if (prod->del_consumer)
0069 prod->del_consumer(prod, cons);
0070
0071 if (cons->start)
0072 cons->start(cons);
0073 if (prod->start)
0074 prod->start(prod);
0075 }
0076
0077
0078
0079
0080
0081
0082
0083
0084 int irq_bypass_register_producer(struct irq_bypass_producer *producer)
0085 {
0086 struct irq_bypass_producer *tmp;
0087 struct irq_bypass_consumer *consumer;
0088 int ret;
0089
0090 if (!producer->token)
0091 return -EINVAL;
0092
0093 might_sleep();
0094
0095 if (!try_module_get(THIS_MODULE))
0096 return -ENODEV;
0097
0098 mutex_lock(&lock);
0099
0100 list_for_each_entry(tmp, &producers, node) {
0101 if (tmp->token == producer->token) {
0102 ret = -EBUSY;
0103 goto out_err;
0104 }
0105 }
0106
0107 list_for_each_entry(consumer, &consumers, node) {
0108 if (consumer->token == producer->token) {
0109 ret = __connect(producer, consumer);
0110 if (ret)
0111 goto out_err;
0112 break;
0113 }
0114 }
0115
0116 list_add(&producer->node, &producers);
0117
0118 mutex_unlock(&lock);
0119
0120 return 0;
0121 out_err:
0122 mutex_unlock(&lock);
0123 module_put(THIS_MODULE);
0124 return ret;
0125 }
0126 EXPORT_SYMBOL_GPL(irq_bypass_register_producer);
0127
0128
0129
0130
0131
0132
0133
0134
0135 void irq_bypass_unregister_producer(struct irq_bypass_producer *producer)
0136 {
0137 struct irq_bypass_producer *tmp;
0138 struct irq_bypass_consumer *consumer;
0139
0140 if (!producer->token)
0141 return;
0142
0143 might_sleep();
0144
0145 if (!try_module_get(THIS_MODULE))
0146 return;
0147
0148 mutex_lock(&lock);
0149
0150 list_for_each_entry(tmp, &producers, node) {
0151 if (tmp->token != producer->token)
0152 continue;
0153
0154 list_for_each_entry(consumer, &consumers, node) {
0155 if (consumer->token == producer->token) {
0156 __disconnect(producer, consumer);
0157 break;
0158 }
0159 }
0160
0161 list_del(&producer->node);
0162 module_put(THIS_MODULE);
0163 break;
0164 }
0165
0166 mutex_unlock(&lock);
0167
0168 module_put(THIS_MODULE);
0169 }
0170 EXPORT_SYMBOL_GPL(irq_bypass_unregister_producer);
0171
0172
0173
0174
0175
0176
0177
0178
0179 int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer)
0180 {
0181 struct irq_bypass_consumer *tmp;
0182 struct irq_bypass_producer *producer;
0183 int ret;
0184
0185 if (!consumer->token ||
0186 !consumer->add_producer || !consumer->del_producer)
0187 return -EINVAL;
0188
0189 might_sleep();
0190
0191 if (!try_module_get(THIS_MODULE))
0192 return -ENODEV;
0193
0194 mutex_lock(&lock);
0195
0196 list_for_each_entry(tmp, &consumers, node) {
0197 if (tmp->token == consumer->token || tmp == consumer) {
0198 ret = -EBUSY;
0199 goto out_err;
0200 }
0201 }
0202
0203 list_for_each_entry(producer, &producers, node) {
0204 if (producer->token == consumer->token) {
0205 ret = __connect(producer, consumer);
0206 if (ret)
0207 goto out_err;
0208 break;
0209 }
0210 }
0211
0212 list_add(&consumer->node, &consumers);
0213
0214 mutex_unlock(&lock);
0215
0216 return 0;
0217 out_err:
0218 mutex_unlock(&lock);
0219 module_put(THIS_MODULE);
0220 return ret;
0221 }
0222 EXPORT_SYMBOL_GPL(irq_bypass_register_consumer);
0223
0224
0225
0226
0227
0228
0229
0230
0231 void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer)
0232 {
0233 struct irq_bypass_consumer *tmp;
0234 struct irq_bypass_producer *producer;
0235
0236 if (!consumer->token)
0237 return;
0238
0239 might_sleep();
0240
0241 if (!try_module_get(THIS_MODULE))
0242 return;
0243
0244 mutex_lock(&lock);
0245
0246 list_for_each_entry(tmp, &consumers, node) {
0247 if (tmp != consumer)
0248 continue;
0249
0250 list_for_each_entry(producer, &producers, node) {
0251 if (producer->token == consumer->token) {
0252 __disconnect(producer, consumer);
0253 break;
0254 }
0255 }
0256
0257 list_del(&consumer->node);
0258 module_put(THIS_MODULE);
0259 break;
0260 }
0261
0262 mutex_unlock(&lock);
0263
0264 module_put(THIS_MODULE);
0265 }
0266 EXPORT_SYMBOL_GPL(irq_bypass_unregister_consumer);