summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-03-24 14:32:23 +0000
committerShaun Ruffell <sruffell@digium.com>2010-03-24 14:32:23 +0000
commit402616d12f9b6e87176636a3d8f83fbfe97a736f (patch)
tree8bfe32fc6f746c5c4f1162eb1bd14e4e8bdb51a7
parent480be7cc68cdaf1a0031f015ec14915256941fc9 (diff)
wcte12xp: t1xxp_maint can be called from interrupt context.
Since t1xxp_maint can be called from interrupt context with the DAHDI_MAINT_LOOPSTOP cmd, push the processing of that command to a workqueue since it may sleep in the t1_getreg call. DAHDI-560. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8410 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wcte12xp/base.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 1dcd4ae..b7f2c9d 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -1114,11 +1114,55 @@ static inline void t1_check_sigbits(struct t1 *wc)
}
}
+struct maint_loopstop_work {
+ struct work_struct work;
+ struct t1 *wc;
+ struct dahdi_span *span;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void t1xxp_maint_loopstop_work(void *data)
+{
+ struct maint_loopstop_work *w = data;
+#else
+static void t1xxp_maint_loopstop_work(struct work_struct *work)
+{
+ struct maint_loopstop_work *w = container_of(work, struct maint_loopstop_work, work);
+#endif
+ t1xxp_clear_maint(w->span);
+ t1_setreg(w->wc, 0x21, 0x40);
+ kfree(w);
+}
+
+static void t1xxp_maint_loopstop(struct t1 *wc, struct dahdi_span *span)
+{
+ struct maint_loopstop_work *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work) {
+ t1_info(wc, "Failed to allocate memory for DAHDI_MAINT_LOOPSTOP\n");
+ return;
+ }
+
+ work->span = span;
+ work->wc = wc;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&work->work, t1xxp_maint_loopstop_work, work);
+#else
+ INIT_WORK(&work->work, t1xxp_maint_loopstop_work);
+#endif
+ schedule_work(&work->work);
+}
+
static int t1xxp_maint(struct dahdi_span *span, int cmd)
{
struct t1 *wc = span->pvt;
int reg = 0;
+ if (DAHDI_MAINT_LOOPSTOP != cmd)
+ might_sleep();
+
if (wc->spantype == TYPE_E1) {
switch (cmd) {
case DAHDI_MAINT_NONE:
@@ -1177,8 +1221,7 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
t1_setreg(wc, 0x21, 0x60);
break;
case DAHDI_MAINT_LOOPSTOP:
- t1xxp_clear_maint(span);
- t1_setreg(wc, 0x21, 0x40);
+ t1xxp_maint_loopstop(wc, span);
break;
default:
t1_info(wc, "Unknown T1 maint command: %d\n", cmd);