summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-02-15 12:23:10 -0600
committerShaun Ruffell <sruffell@digium.com>2011-04-15 14:19:00 -0500
commit04701db43edce96ad9f9d35ee63e36f415e62b55 (patch)
tree5c77bf7165e008d0de86c20f4bd9a57f16329c68
parent7a3366a637242abb009bf9d3c7b708d80a5f1aee (diff)
wctdm24xxp: Use lists for SPI commands to the modules.
Saves time in the interrupt handler by eliminating the need to scan through all of the slots in the cmd arrays. Also allows the reads from ISR context to automatically grow as the latency grows. This ensures that battery and hook state is actually checked every frame like originally intended. Signed-off-by: Shaun Ruffell <sruffell@digium.com>
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c379
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h20
2 files changed, 227 insertions, 172 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index b04a908..d13ec1b 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -279,16 +279,6 @@ static inline int CMD_BYTE(int card, int bit, int altcs)
+ ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0));
}
-static inline int empty_slot(struct wctdm_module *const mod)
-{
- int x;
- for (x = 0; x < USER_COMMANDS; x++) {
- if (!mod->cmdq.cmds[x])
- return x;
- }
- return -1;
-}
-
static void
setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
GpakChannelConfig_t *chanconfig)
@@ -584,11 +574,11 @@ static void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *eframe)
}
}
+/* Call with wc->reglock held and local interrupts disabled */
static void _cmd_dequeue(struct wctdm *wc, u8 *eframe, int card, int pos)
{
struct wctdm_module *const mod = &wc->mods[card];
unsigned int curcmd=0;
- int x;
int subaddr = card & 0x3;
/* QRV only use commands relating to the first channel */
@@ -602,13 +592,13 @@ static void _cmd_dequeue(struct wctdm *wc, u8 *eframe, int card, int pos)
eframe += 24;
/* Search for something waiting to transmit */
if (pos) {
- for (x = 0; x < MAX_COMMANDS; x++) {
- if ((mod->cmdq.cmds[x] & (__CMD_RD | __CMD_WR)) &&
- !(mod->cmdq.cmds[x] & (__CMD_TX | __CMD_FIN))) {
- curcmd = mod->cmdq.cmds[x];
- mod->cmdq.cmds[x] |= (wc->txident << 24) | __CMD_TX;
- break;
- }
+ if (!list_empty(&mod->pending_cmds)) {
+ struct wctdm_cmd *const cmd =
+ list_entry(mod->pending_cmds.next,
+ struct wctdm_cmd, node);
+ curcmd = cmd->cmd;
+ cmd->ident = wc->txident;
+ list_move_tail(&cmd->node, &mod->active_cmds);
}
}
@@ -742,71 +732,132 @@ static inline void cmd_decipher_vpmadt032(struct wctdm *wc, const u8 *eframe)
*/
static void _cmd_decipher(struct wctdm *wc, const u8 *eframe, int card)
{
+ enum { TDM_BYTES = 24, };
struct wctdm_module *const mod = &wc->mods[card];
- unsigned char ident;
- int x;
+ struct wctdm_cmd *cmd;
+ u8 address;
+ u8 value;
- /* QRV modules only use commands relating to the first channel */
- if ((card & 0x03) && (mod->type == QRV))
+ if (list_empty(&mod->active_cmds))
return;
- /* Skip audio */
- eframe += 24;
+ cmd = list_entry(mod->active_cmds.next, struct wctdm_cmd, node);
+ if (cmd->ident != wc->rxident)
+ return;
- /* Search for any pending results */
- for (x=0;x<MAX_COMMANDS;x++) {
- if ((mod->cmdq.cmds[x] & (__CMD_RD | __CMD_WR)) &&
- (mod->cmdq.cmds[x] & (__CMD_TX)) &&
- !(mod->cmdq.cmds[x] & (__CMD_FIN))) {
- ident = (mod->cmdq.cmds[x] >> 24) & 0xff;
- if (ident == wc->rxident) {
- /* Store result */
- mod->cmdq.cmds[x] |= eframe[CMD_BYTE(card, 2, mod->altcs)];
- mod->cmdq.cmds[x] |= __CMD_FIN;
- if (mod->cmdq.cmds[x] & __CMD_WR) {
- /* Go ahead and clear out writes since they need no acknowledgement */
- mod->cmdq.cmds[x] = 0x00000000;
- } else if (x >= USER_COMMANDS) {
- /* Clear out ISR reads */
- mod->cmdq.isrshadow[x - USER_COMMANDS] = mod->cmdq.cmds[x] & 0xff;
- mod->cmdq.cmds[x] = 0x00000000;
- }
- break;
- }
+ list_del(&cmd->node);
+
+ if (cmd->cmd & __CMD_WR) {
+ kfree(cmd);
+ return;
+ }
+
+ address = (cmd->cmd >> 8) & 0xff;
+
+ cmd->cmd = eframe[TDM_BYTES + CMD_BYTE(card, 2, mod->altcs)];
+
+ value = (cmd->cmd & 0xff);
+
+ if (cmd->complete) {
+ complete(cmd->complete);
+ return;
+ }
+
+ switch (mod->type) {
+ case FXS:
+ if (68 == address) {
+ mod->isrshadow[0] = value;
+#ifdef PAQ_DEBUG
+ } else if (19 == address) {
+ mod->isrshadow[1] = value;
+#else
+ } else if (LINE_STATE == address) {
+ mod->isrshadow[1] = value;
+#endif
+ } else {
+ dev_info(&wc->vb.pdev->dev,
+ "FXS isr read address: %d\n", address);
+ }
+ break;
+ case FXO:
+ if (5 == address) { /* Hook/Ring state */
+ mod->isrshadow[0] = value;
+ } else if (29 == address) { /* Battery */
+ mod->isrshadow[1] = value;
+ } else {
+ dev_info(&wc->vb.pdev->dev,
+ "FXO isr read address: %d %08x\n",
+ address, cmd->cmd);
}
+ break;
+ case QRV:
+ /* wctdm_isr_getreg(wc, mod, 3); */ /* COR/CTCSS state */
+ /* TODO: This looks broken to me, but I have no way to
+ * resolved it. */
+ /* wc->mods[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3); */
+ break;
+ default:
+ break;
}
+
+ kfree(cmd);
}
+/* Call with wc.reglock held and local interrupts disabled. */
+static void
+wctdm_isr_getreg(struct wctdm *wc, struct wctdm_module *const mod, u8 address)
+{
+ struct wctdm_cmd *cmd;
+
+ cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (unlikely(!cmd))
+ return;
+
+ cmd->cmd = CMD_RD(address);
+ cmd->complete = NULL;
+
+ list_add(&cmd->node, &mod->pending_cmds);
+}
+
+static inline void
+wctdm_setreg_intr(struct wctdm *wc, struct wctdm_module *mod,
+ int addr, int val);
+
static void cmd_checkisr(struct wctdm *wc, struct wctdm_module *const mod)
{
- if (!mod->cmdq.cmds[USER_COMMANDS + 0]) {
- if (mod->sethook) {
- mod->cmdq.cmds[USER_COMMANDS + 0] = mod->sethook;
- mod->sethook = 0;
- } else if (mod->type == FXS) {
- mod->cmdq.cmds[USER_COMMANDS + 0] = CMD_RD(68); /* Hook state */
- } else if (mod->type == FXO) {
- mod->cmdq.cmds[USER_COMMANDS + 0] = CMD_RD(5); /* Hook/Ring state */
- } else if (mod->type == QRV) {
- wc->mods[mod->card & 0xfc].cmdq.cmds[USER_COMMANDS + 0] = CMD_RD(3); /* COR/CTCSS state */
- } else if (mod->type == BRI) {
- wctdm_bri_checkisr(wc, mod, 0);
- }
+ if (mod->sethook) {
+ wctdm_setreg_intr(wc, mod, ((mod->sethook >> 8) & 0xff),
+ mod->sethook & 0xff);
+ mod->sethook = 0;
+ return;
}
- if (!mod->cmdq.cmds[USER_COMMANDS + 1]) {
- if (mod->type == FXS) {
+
+ switch (mod->type) {
+ case FXS:
+ wctdm_isr_getreg(wc, mod, 68); /* Hook state */
#ifdef PAQ_DEBUG
- mod->cmdq.cmds[USER_COMMANDS + 1] = CMD_RD(19); /* Transistor interrupts */
+ wctdm_isr_getreg(wc, mod, 19); /* Transistor interrupts */
#else
- mod->cmdq.cmds[USER_COMMANDS + 1] = CMD_RD(LINE_STATE);
+ wctdm_isr_getreg(wc, mod, LINE_STATE);
#endif
- } else if (mod->type == FXO) {
- mod->cmdq.cmds[USER_COMMANDS + 1] = CMD_RD(29); /* Battery */
- } else if (mod->type == QRV) {
- wc->mods[mod->card & 0xfc].cmdq.cmds[USER_COMMANDS + 1] = CMD_RD(3); /* Battery */
- } else if (mod->type == BRI) {
- wctdm_bri_checkisr(wc, mod, 1);
- }
+ break;
+ case FXO:
+ wctdm_isr_getreg(wc, mod, 5); /* Hook/Ring state */
+ wctdm_isr_getreg(wc, mod, 29); /* Battery */
+ break;
+ case QRV:
+ wctdm_isr_getreg(wc, mod, 3); /* COR/CTCSS state */
+ /* TODO: This looks broken to me, but I have no way to
+ * resolved it. */
+ /* wc->mods[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3); */
+ break;
+ case BRI:
+ /* TODO: Two calls needed here? */
+ wctdm_bri_checkisr(wc, mod, 0);
+ wctdm_bri_checkisr(wc, mod, 1);
+ break;
+ default:
+ break;
}
}
@@ -920,28 +971,26 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *sframe)
spin_unlock_irqrestore(&wc->reglock, flags);
}
-static bool
-stuff_command(struct wctdm *wc, struct wctdm_module *const mod,
- unsigned int cmd, int *hit)
+/* Must be called with wc.reglock held and local interrupts disabled */
+static inline void
+wctdm_setreg_intr(struct wctdm *wc, struct wctdm_module *mod, int addr, int val)
{
- unsigned long flags;
+ struct wctdm_cmd *cmd;
- spin_lock_irqsave(&wc->reglock, flags);
- *hit = empty_slot(mod);
- if (*hit > -1)
- mod->cmdq.cmds[*hit] = cmd;
- spin_unlock_irqrestore(&wc->reglock, flags);
+ cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (unlikely(!cmd))
+ return;
+
+ cmd->complete = NULL;
+ cmd->cmd = CMD_WR(addr, val);
- return (*hit > -1);
+ list_add_tail(&cmd->node, &mod->pending_cmds);
}
-static int
-wctdm_setreg_full(struct wctdm *wc, struct wctdm_module *mod,
- int addr, int val, int inisr)
+int wctdm_setreg(struct wctdm *wc, struct wctdm_module *mod, int addr, int val)
{
- const unsigned int cmd = CMD_WR(addr, val);
- int ret;
- int hit;
+ struct wctdm_cmd *cmd;
+ unsigned long flags;
#if 0 /* TODO */
/* QRV and BRI cards are only addressed at their first "port" */
@@ -950,52 +999,25 @@ wctdm_setreg_full(struct wctdm *wc, struct wctdm_module *mod,
return 0;
#endif
- if (inisr) {
- stuff_command(wc, mod, cmd, &hit);
- return 0;
- }
-
- ret = wait_event_interruptible(wc->regq,
- stuff_command(wc, mod, cmd, &hit));
- return ret;
-}
-
-static inline void
-wctdm_setreg_intr(struct wctdm *wc, struct wctdm_module *mod, int addr, int val)
-{
- wctdm_setreg_full(wc, mod, addr, val, 1);
-}
-
-int wctdm_setreg(struct wctdm *wc, struct wctdm_module *mod, int addr, int val)
-{
- return wctdm_setreg_full(wc, mod, addr, val, 0);
-}
+ cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ if (unlikely(!cmd))
+ return -ENOMEM;
-static bool
-cmd_finished(struct wctdm *wc, struct wctdm_module *const mod, int hit, u8 *val)
-{
- bool ret;
- unsigned long flags;
+ cmd->complete = NULL;
+ cmd->cmd = CMD_WR(addr, val);
spin_lock_irqsave(&wc->reglock, flags);
- if (mod->cmdq.cmds[hit] & __CMD_FIN) {
- *val = mod->cmdq.cmds[hit] & 0xff;
- mod->cmdq.cmds[hit] = 0x00000000;
- ret = true;
- } else {
- ret = false;
- }
+ list_add_tail(&cmd->node, &mod->pending_cmds);
spin_unlock_irqrestore(&wc->reglock, flags);
- return ret;
+ return 0;
}
int wctdm_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr)
{
- const unsigned int cmd = CMD_RD(addr);
- u8 val = 0;
- int hit;
- int ret;
+ unsigned long flags;
+ struct wctdm_cmd *cmd;
+ int val;
#if 0 /* TODO */
/* if a QRV card, use only its first channel */
@@ -1005,15 +1027,29 @@ int wctdm_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr)
}
#endif
- ret = wait_event_interruptible(wc->regq,
- stuff_command(wc, mod, cmd, &hit));
- if (ret)
- return ret;
+ cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
- ret = wait_event_interruptible(wc->regq,
- cmd_finished(wc, mod, hit, &val));
- if (ret)
- return ret;
+ cmd->complete = kmalloc(sizeof(*cmd->complete), GFP_KERNEL);
+ if (!cmd->complete) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ init_completion(cmd->complete);
+
+ cmd->cmd = CMD_RD(addr);
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ list_add_tail(&cmd->node, &mod->pending_cmds);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ wait_for_completion(cmd->complete);
+ val = cmd->cmd & 0xff;
+
+ kfree(cmd->complete);
+ kfree(cmd);
return val;
}
@@ -1023,17 +1059,15 @@ int wctdm_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr)
*/
static void cmd_retransmit(struct wctdm *wc)
{
- int x,y;
- /* Force retransmissions */
- for (x=0;x<MAX_COMMANDS;x++) {
- for (y = 0; y < wc->mods_per_board; y++) {
- struct wctdm_module *const mod = &wc->mods[y];
- if (mod->type == BRI)
- continue;
- if (!(mod->cmdq.cmds[x] & __CMD_FIN))
- mod->cmdq.cmds[x] &= ~(__CMD_TX | (0xff << 24));
- }
+ int x;
+
+ for (x = 0; x < wc->mods_per_board; x++) {
+ struct wctdm_module *const mod = &wc->mods[x];
+ if (mod->type == BRI)
+ continue;
+ list_splice_init(&mod->active_cmds, &mod->pending_cmds);
}
+
#ifdef VPM_SUPPORT
if (wc->vpmadt032)
vpmadt032_resend(wc->vpmadt032);
@@ -1158,9 +1192,6 @@ static inline void wctdm_receiveprep(struct wctdm *wc, const u8 *sframe)
}
}
}
-
- /* Wake up anyone sleeping to read/write a new register */
- wake_up_interruptible_all(&wc->regq);
}
static int wait_access(struct wctdm *wc, struct wctdm_module *const mod)
@@ -1301,20 +1332,21 @@ static void
wctdm_proslic_check_oppending(struct wctdm *wc, struct wctdm_module *const mod)
{
struct fxs *const fxs = &mod->mod.fxs;
+ unsigned long flags;
int res;
if (!(fxs->lasttxhook & SLIC_LF_OPPENDING))
return;
/* Monitor the Pending LF state change, for the next 100ms */
- spin_lock(&fxs->lasttxhooklock);
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
if (!(fxs->lasttxhook & SLIC_LF_OPPENDING)) {
- spin_unlock(&fxs->lasttxhooklock);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
return;
}
- res = mod->cmdq.isrshadow[1];
+ res = mod->isrshadow[1];
if ((res & SLIC_LF_SETMASK) == (fxs->lasttxhook & SLIC_LF_SETMASK)) {
fxs->lasttxhook &= SLIC_LF_SETMASK;
fxs->oppending_ms = 0;
@@ -1325,8 +1357,7 @@ wctdm_proslic_check_oppending(struct wctdm *wc, struct wctdm_module *const mod)
res, fxs->lasttxhook, wc->intcount);
}
} else if (fxs->oppending_ms && (--fxs->oppending_ms == 0)) {
- /* Timed out, resend the linestate */
- mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ wctdm_setreg_intr(wc, mod, LINE_STATE, fxs->lasttxhook);
if (debug & DEBUG_CARD) {
dev_info(&wc->vb.pdev->dev,
"SLIC_LF RETRY: card=%d shadow=%02x "
@@ -1336,7 +1367,7 @@ wctdm_proslic_check_oppending(struct wctdm *wc, struct wctdm_module *const mod)
} else { /* Start 100ms Timeout */
fxs->oppending_ms = 100;
}
- spin_unlock(&fxs->lasttxhooklock);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
}
/* 256ms interrupt */
@@ -1347,16 +1378,16 @@ wctdm_proslic_recheck_sanity(struct wctdm *wc, struct wctdm_module *const mod)
int res;
unsigned long flags;
#ifdef PAQ_DEBUG
- res = mod->cmdq.isrshadow[1];
+ res = mod->isrshadow[1];
res &= ~0x3;
if (res) {
- mod->cmdq.isrshadow[1] = 0;
+ mod->isrshadow[1] = 0;
fxs->palarms++;
if (fxs->palarms < MAX_ALARMS) {
dev_notice(&wc->vb.pdev->dev, "Power alarm (%02x) on module %d, resetting!\n", res, card + 1);
mod->sethook = CMD_WR(19, res);
/* Update shadow register to avoid extra power alarms until next read */
- mod->cmdq.isrshadow[1] = 0;
+ mod->isrshadow[1] = 0;
} else {
if (fxs->palarms == MAX_ALARMS)
dev_notice(&wc->vb.pdev->dev, "Too many power alarms on card %d, NOT resetting!\n", card + 1);
@@ -1364,7 +1395,7 @@ wctdm_proslic_recheck_sanity(struct wctdm *wc, struct wctdm_module *const mod)
}
#else
spin_lock_irqsave(&fxs->lasttxhooklock, flags);
- res = mod->cmdq.isrshadow[1];
+ res = mod->isrshadow[1];
#if 0
/* This makes sure the lasthook was put in reg 64 the linefeed reg */
@@ -1410,7 +1441,7 @@ wctdm_proslic_recheck_sanity(struct wctdm *wc, struct wctdm_module *const mod)
spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
/* Update shadow register to avoid extra power alarms until next read */
- mod->cmdq.isrshadow[1] = fxs->lasttxhook;
+ mod->isrshadow[1] = fxs->lasttxhook;
} else {
if (fxs->palarms == MAX_ALARMS) {
dev_notice(&wc->vb.pdev->dev,
@@ -1429,7 +1460,7 @@ static void wctdm_qrvdri_check_hook(struct wctdm *wc, int card)
if (wc->mods[card].mod.qrv.debtime >= 2)
wc->mods[card].mod.qrv.debtime--;
- b = wc->mods[qrvcard].cmdq.isrshadow[0]; /* Hook/Ring state */
+ b = wc->mods[qrvcard].isrshadow[0]; /* Hook/Ring state */
b &= 0xcc; /* use bits 3-4 and 6-7 only */
if (wc->mods[qrvcard].mod.qrv.radmode & RADMODE_IGNORECOR)
@@ -1501,7 +1532,7 @@ wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod)
struct fxo *const fxo = &mod->mod.fxo;
/* Try to track issues that plague slot one FXO's */
- b = mod->cmdq.isrshadow[0]; /* Hook/Ring state */
+ b = mod->isrshadow[0]; /* Hook/Ring state */
b &= 0x9b;
if (fxo->offhook) {
if (b != 0x9)
@@ -1521,7 +1552,7 @@ wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod)
* but not to have transitions between the two bits (i.e. no negative
* to positive or positive to negative transversals )
*/
- res = mod->cmdq.isrshadow[0] & 0x60;
+ res = mod->isrshadow[0] & 0x60;
if (0 == fxo->wasringing) {
if (res) {
/* Look for positive/negative crossings in ring status reg */
@@ -1559,7 +1590,7 @@ wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod)
}
}
} else {
- res = mod->cmdq.isrshadow[0];
+ res = mod->isrshadow[0];
if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) {
fxo->ringdebounce += (DAHDI_CHUNKSIZE * 16);
if (fxo->ringdebounce >= DAHDI_CHUNKSIZE * ringdebounce) {
@@ -1587,7 +1618,7 @@ wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod)
}
}
- b = mod->cmdq.isrshadow[1]; /* Voltage */
+ b = mod->isrshadow[1]; /* Voltage */
abs_voltage = abs(b);
if (fxovoltage) {
@@ -1895,7 +1926,7 @@ wctdm_proslic_check_hook(struct wctdm *wc, struct wctdm_module *const mod)
/* For some reason we have to debounce the
hook detector. */
- res = mod->cmdq.isrshadow[0]; /* Hook state */
+ res = mod->isrshadow[0]; /* Hook state */
hook = (res & 1);
if (hook != fxs->lastrxhook) {
@@ -2256,6 +2287,10 @@ wctdm_proslic_powerleak_test(struct wctdm *wc, struct wctdm_module *const mod)
/* Wait for one second */
origjiffies = jiffies;
+ /* TODO: Why is this sleep necessary. WIthout it, the first read
+ * comes back with a 0 value. */
+ msleep(20);
+
while ((vbat = wctdm_getreg(wc, mod, 82)) > 0x6) {
if ((jiffies - origjiffies) >= (HZ/2))
break;;
@@ -4251,7 +4286,6 @@ static void wctdm_back_out_gracefully(struct wctdm *wc)
{
int i;
unsigned long flags;
- struct sframe_packet *frame;
LIST_HEAD(local_list);
voicebus_release(&wc->vb);
@@ -4270,9 +4304,23 @@ static void wctdm_back_out_gracefully(struct wctdm *wc)
wc->spans[i] = NULL;
}
+ spin_lock_irqsave(&wc->reglock, flags);
for (i = 0; i < ARRAY_SIZE(wc->mods); ++i) {
- kfree(wc->mods[i].chan);
- wc->mods[i].chan = NULL;
+ struct wctdm_module *const mod = &wc->mods[i];
+ kfree(mod->chan);
+ mod->chan = NULL;
+ list_splice_init(&mod->pending_cmds, &local_list);
+ list_splice_init(&mod->active_cmds, &local_list);
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ while (!list_empty(&local_list)) {
+ struct wctdm_cmd *cmd;
+ cmd = list_entry(local_list.next,
+ struct wctdm_cmd, node);
+ list_del(&cmd->node);
+ kfree(cmd->complete);
+ kfree(cmd);
}
spin_lock_irqsave(&wc->frame_list_lock, flags);
@@ -4280,12 +4328,15 @@ static void wctdm_back_out_gracefully(struct wctdm *wc)
spin_unlock_irqrestore(&wc->frame_list_lock, flags);
while (!list_empty(&local_list)) {
+ struct sframe_packet *frame;
frame = list_entry(local_list.next,
struct sframe_packet, node);
list_del(&frame->node);
kfree(frame);
}
+
+
kfree(wc->board_name);
kfree(wc);
}
@@ -4910,7 +4961,9 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Auto detect this card's companding */
wc->companding = DAHDI_LAW_DEFAULT;
- for (i = 0; i < NUM_MODULES; i++) {
+ for (i = 0; i < ARRAY_SIZE(wc->mods); i++) {
+ INIT_LIST_HEAD(&wc->mods[i].pending_cmds);
+ INIT_LIST_HEAD(&wc->mods[i].active_cmds);
wc->mods[i].dacssrc = -1;
wc->mods[i].card = i;
}
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index e88eaaf..eccbea9 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -85,12 +85,9 @@
#define NUM_CAL_REGS 12
-#define USER_COMMANDS 8
#define ISR_COMMANDS 2
#define QRV_DEBOUNCETIME 20
-#define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS)
-
#define VPM150M_HPI_CONTROL 0x00
#define VPM150M_HPI_ADDRESS 0x02
#define VPM150M_HPI_DATA 0x03
@@ -106,17 +103,19 @@ struct calregs {
unsigned char vals[NUM_CAL_REGS];
};
-struct cmdq {
- unsigned int cmds[MAX_COMMANDS];
- unsigned char isrshadow[ISR_COMMANDS];
-};
-
enum battery_state {
BATTERY_UNKNOWN = 0,
BATTERY_PRESENT,
BATTERY_LOST,
};
+struct wctdm_cmd {
+ struct list_head node;
+ struct completion *complete;
+ u32 cmd;
+ u8 ident;
+};
+
/**
* struct wctdm_span -
* @span: dahdi_span to register.
@@ -222,7 +221,10 @@ struct wctdm_module {
struct b400m *bri;
} mod;
- struct cmdq cmdq;
+ /* Protected by wctdm.reglock */
+ struct list_head pending_cmds;
+ struct list_head active_cmds;
+ u8 isrshadow[ISR_COMMANDS];
enum module_type type;
int sethook; /* pending hook state command */