summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-03-24 15:39:05 +0000
committerShaun Ruffell <sruffell@digium.com>2010-03-24 15:39:05 +0000
commit9521077178a3568713477ab8e0b80646cadffa0e (patch)
tree28e2004926943673d260ec6b512b2bea245a9206
parent402616d12f9b6e87176636a3d8f83fbfe97a736f (diff)
wcte12xp: t1xxp_maint is also called with interrupts disabled from dahdi_ioctl
So just push all the maintenance mode processing off to the workqueue. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8415 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wcte12xp/base.c117
1 files changed, 75 insertions, 42 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index b7f2c9d..f56f3b5 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -1114,54 +1114,28 @@ static inline void t1_check_sigbits(struct t1 *wc)
}
}
-struct maint_loopstop_work {
+struct maint_work_struct {
struct work_struct work;
struct t1 *wc;
+ int cmd;
struct dahdi_span *span;
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-static void t1xxp_maint_loopstop_work(void *data)
+static void t1xxp_maint_work(void *data)
{
- struct maint_loopstop_work *w = data;
+ struct maint_work_struct *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);
+ struct maint_work_struct *w = container_of(work,
+ struct maint_work_struct, 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;
+ struct t1 *wc = w->wc;
+ struct dahdi_span *span = w->span;
int reg = 0;
-
- if (DAHDI_MAINT_LOOPSTOP != cmd)
- might_sleep();
+ int cmd = w->cmd;
if (wc->spantype == TYPE_E1) {
switch (cmd) {
@@ -1173,7 +1147,7 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
t1xxp_clear_maint(span);
reg = t1_getreg(wc, LIM0);
if (reg < 0)
- return -EIO;
+ goto cleanup;
t1_setreg(wc, LIM0, reg | LIM0_LL);
break;
case DAHDI_MAINT_REMOTELOOP:
@@ -1181,10 +1155,10 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
case DAHDI_MAINT_LOOPDOWN:
case DAHDI_MAINT_LOOPSTOP:
t1_info(wc, "Only local loop supported in E1 mode\n");
- return -ENOSYS;
+ goto cleanup;
default:
t1_info(wc, "Unknown E1 maint command: %d\n", cmd);
- return -ENOSYS;
+ goto cleanup;
}
} else {
switch (cmd) {
@@ -1195,21 +1169,21 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
t1xxp_clear_maint(span);
reg = t1_getreg(wc, LIM0);
if (reg < 0)
- return -EIO;
+ goto cleanup;
t1_setreg(wc, LIM0, reg | LIM0_LL);
break;
case DAHDI_MAINT_NETWORKLINELOOP:
t1xxp_clear_maint(span);
reg = t1_getreg(wc, LIM1);
if (reg < 0)
- return -EIO;
+ goto cleanup;
t1_setreg(wc, LIM1, reg | LIM1_RL);
break;
case DAHDI_MAINT_NETWORKPAYLOADLOOP:
t1xxp_clear_maint(span);
reg = t1_getreg(wc, LIM1);
if (reg < 0)
- return -EIO;
+ goto cleanup;
t1_setreg(wc, LIM1, reg | (LIM1_RL | LIM1_JATT));
break;
case DAHDI_MAINT_LOOPUP:
@@ -1221,7 +1195,49 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
t1_setreg(wc, 0x21, 0x60);
break;
case DAHDI_MAINT_LOOPSTOP:
- t1xxp_maint_loopstop(wc, span);
+ t1xxp_clear_maint(w->span);
+ t1_setreg(w->wc, 0x21, 0x40);
+ break;
+ default:
+ t1_info(wc, "Unknown T1 maint command: %d\n", cmd);
+ return;
+ }
+ }
+
+cleanup:
+ kfree(w);
+ return;
+}
+
+static int t1xxp_maint(struct dahdi_span *span, int cmd)
+{
+ struct maint_work_struct *work;
+ struct t1 *wc = span->pvt;
+
+ if (wc->spantype == TYPE_E1) {
+ switch (cmd) {
+ case DAHDI_MAINT_NONE:
+ case DAHDI_MAINT_LOCALLOOP:
+ break;
+ case DAHDI_MAINT_REMOTELOOP:
+ case DAHDI_MAINT_LOOPUP:
+ case DAHDI_MAINT_LOOPDOWN:
+ case DAHDI_MAINT_LOOPSTOP:
+ t1_info(wc, "Only local loop supported in E1 mode\n");
+ return -ENOSYS;
+ default:
+ t1_info(wc, "Unknown E1 maint command: %d\n", cmd);
+ return -ENOSYS;
+ }
+ } else {
+ switch (cmd) {
+ case DAHDI_MAINT_NONE:
+ case DAHDI_MAINT_LOCALLOOP:
+ case DAHDI_MAINT_NETWORKLINELOOP:
+ case DAHDI_MAINT_NETWORKPAYLOADLOOP:
+ case DAHDI_MAINT_LOOPUP:
+ case DAHDI_MAINT_LOOPDOWN:
+ case DAHDI_MAINT_LOOPSTOP:
break;
default:
t1_info(wc, "Unknown T1 maint command: %d\n", cmd);
@@ -1229,6 +1245,23 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
}
}
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work) {
+ t1_info(wc, "Failed to allocate memory for "
+ "DAHDI_MAINT_LOOPSTOP\n");
+ return -ENOMEM;
+ }
+
+ work->span = span;
+ work->wc = wc;
+ work->cmd = cmd;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&work->work, t1xxp_maint_work, work);
+#else
+ INIT_WORK(&work->work, t1xxp_maint_work);
+#endif
+ schedule_work(&work->work);
return 0;
}