summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctdm24xxp/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi/wctdm24xxp/base.c')
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c89
1 files changed, 80 insertions, 9 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 8990d70..9b16d80 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -473,6 +473,16 @@ static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
return 0;
}
+/**
+ * is_good_frame() - Whether the SFRAME received was one sent.
+ *
+ */
+static inline bool is_good_frame(const u8 *sframe)
+{
+ const u8 a = sframe[0*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)];
+ const u8 b = sframe[1*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)];
+ return a != b;
+}
static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *writechunk, int whichframe)
{
@@ -1017,12 +1027,68 @@ static inline void cmd_retransmit(struct wctdm *wc)
#endif
}
+/**
+ * extract_tdm_data() - Move TDM data from sframe to channels.
+ *
+ */
+static void extract_tdm_data(struct wctdm *wc, const u8 *sframe)
+{
+ int i;
+ register u8 *chanchunk;
+
+ for (i = 0; i < wc->cards; i += 4) {
+ chanchunk = &wc->chans[0 + i]->readchunk[0];
+ chanchunk[0] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
+ chanchunk[1] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
+ chanchunk[2] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
+ chanchunk[3] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*3];
+ chanchunk[4] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*4];
+ chanchunk[5] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*5];
+ chanchunk[6] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
+ chanchunk[7] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
+
+ chanchunk = &wc->chans[1 + i]->readchunk[0];
+ chanchunk[0] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
+ chanchunk[1] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
+ chanchunk[2] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
+ chanchunk[3] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*3];
+ chanchunk[4] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*4];
+ chanchunk[5] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*5];
+ chanchunk[6] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
+ chanchunk[7] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
+
+ chanchunk = &wc->chans[2 + i]->readchunk[0];
+ chanchunk[0] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
+ chanchunk[1] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
+ chanchunk[2] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
+ chanchunk[3] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*3];
+ chanchunk[4] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*4];
+ chanchunk[5] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*5];
+ chanchunk[6] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
+ chanchunk[7] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
+
+ chanchunk = &wc->chans[3 + i]->readchunk[0];
+ chanchunk[0] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
+ chanchunk[1] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
+ chanchunk[2] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
+ chanchunk[3] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*3];
+ chanchunk[4] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*4];
+ chanchunk[5] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*5];
+ chanchunk[6] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
+ chanchunk[7] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
+ }
+}
+
static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
{
int x,y;
unsigned char expected;
- BUG_ON(NULL == readchunk);
+ if (unlikely(!is_good_frame(readchunk)))
+ return;
+
+ if (likely(wc->initialized))
+ extract_tdm_data(wc, readchunk);
for (x=0;x<DAHDI_CHUNKSIZE;x++) {
if (x < DAHDI_CHUNKSIZE - 1) {
@@ -1814,20 +1880,25 @@ static inline void wctdm_isr_misc(struct wctdm *wc)
}
}
-static void handle_receive(struct voicebus *vb, void* vbb)
+static void handle_receive(struct voicebus *vb, struct list_head *buffers)
{
struct wctdm *wc = container_of(vb, struct wctdm, vb);
- wctdm_receiveprep(wc, vbb);
+ struct vbb *vbb;
+ list_for_each_entry(vbb, buffers, entry)
+ wctdm_receiveprep(wc, vbb->data);
}
-static void handle_transmit(struct voicebus *vb, void* vbb)
+static void handle_transmit(struct voicebus *vb, struct list_head *buffers)
{
struct wctdm *wc = container_of(vb, struct wctdm, vb);
- memset(vbb, 0, SFRAME_SIZE);
- wctdm_transmitprep(wc, vbb);
- wctdm_isr_misc(wc);
- wc->intcount++;
- voicebus_transmit(&wc->vb, vbb);
+ struct vbb *vbb;
+
+ list_for_each_entry(vbb, buffers, entry) {
+ memset(vbb->data, 0, sizeof(vbb->data));
+ wctdm_transmitprep(wc, vbb->data);
+ wctdm_isr_misc(wc);
+ wc->intcount++;
+ }
}
static int wctdm_voicedaa_insane(struct wctdm *wc, int card)