summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctc4xxp
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2008-08-06 18:09:58 +0000
committerShaun Ruffell <sruffell@digium.com>2008-08-06 18:09:58 +0000
commitcd4763bcfad087a8e2e33464e79b4f69a5f31094 (patch)
treed83edd7008142c8d6c7625b7dde044277925a84f /drivers/dahdi/wctc4xxp
parent44ff5a846de3b86f60ae420e3e67a2827fb68f11 (diff)
A significant change to the DAHDI transcoder interface and the wctc4xxp
driver which breaks backwards compatibility. Basically, I've replaced the memory mapped interface with a read/write interface that allows codec_dahdi to communicate with the hardware transcoder the exact size of the packet to be transcoded. This eliminates issues with remote devices that send G729.B CNG packets even though asterisk does not support them. From a user standpoint: - The transcoder drivers are much more robust in light of system / external conditions. From a developer standpoint: - DAHDI_TRANSCODE_OP is no longer supported, instead use DAHDI_TC_ALLOCATE, DAHDI_TC_GETINFO, and write/read. - Memory and stack usage is reduced (stack usage could still be reduced some more by continuing the process of getting rid of the users of wctc4xxp_send_cmd and wctc4xxp_create_cmd). - If more than one card is in the system channels will be allocated in a round-robin fashion from all available cards, reducing contention for the supervisor channel. - There is no longer a tc400b workqueue created that will not show up in the process list. - Commands and their responses are now explicitly matched up which elimated certain errors caused by unsolicited messages from the transcoder confusing the driver. - There is now an option to export a network interface for capturing traffic to/from the hardware transcoder. - codec_test has been removed from the dadhi/linux package. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4717 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/wctc4xxp')
-rw-r--r--drivers/dahdi/wctc4xxp/Kbuild2
-rw-r--r--drivers/dahdi/wctc4xxp/Makefile9
-rw-r--r--drivers/dahdi/wctc4xxp/base.c4148
-rw-r--r--drivers/dahdi/wctc4xxp/codec_test.c329
4 files changed, 2705 insertions, 1783 deletions
diff --git a/drivers/dahdi/wctc4xxp/Kbuild b/drivers/dahdi/wctc4xxp/Kbuild
index 3794ff7..90e8ef8 100644
--- a/drivers/dahdi/wctc4xxp/Kbuild
+++ b/drivers/dahdi/wctc4xxp/Kbuild
@@ -8,7 +8,7 @@ ifeq ($(HOTPLUG_FIRMWARE),yes)
EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
endif
-wctc4xxp-objs := base.o
+wctc4xxp-objs := base.o
ifneq ($(HOTPLUG_FIRMWARE),yes)
wctc4xxp-objs += $(FIRM_DIR)/dahdi-fw-tc400m.o
diff --git a/drivers/dahdi/wctc4xxp/Makefile b/drivers/dahdi/wctc4xxp/Makefile
index cf5501f..866fdae 100644
--- a/drivers/dahdi/wctc4xxp/Makefile
+++ b/drivers/dahdi/wctc4xxp/Makefile
@@ -3,14 +3,5 @@ ifdef KBUILD_EXTMOD
# For newer kernels, Kbuild will be included directly by the kernel
# build system.
include $(src)/Kbuild
-
else
-
-tests: codec_test
-
-codec_test: codec_test.c ../../include/dahdi/kernel.h ../../include/dahdi/user.h
- $(CC) -o $@ $< $(CFLAGS)
-
-clean:
- rm -rf codec_test
endif
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 9d9a1ed..f41ab0f 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1,9 +1,7 @@
/*
* Wildcard TC400B Driver
*
- * Written by John Sloan <jsloan@digium.com>
- *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -23,90 +21,158 @@
*
*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/mman.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/semaphore.h>
#include <linux/jiffies.h>
-#include <linux/workqueue.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
-#include <dahdi/kernel.h>
-
-
-/* #define USE_TEST_HW */
-#define USE_TDM_CONFIG
-#define QUIET_DSP
-
-#define WC_MAX_IFACES 128
-
-#define NUM_CARDS 24
-#define NUM_EC 4
-
-/* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
-#define NUM_CHANNELS 120
-
-#define DTE_FORMAT_ULAW 0x00
-#define DTE_FORMAT_G723_1 0x04
-#define DTE_FORMAT_ALAW 0x08
-#define DTE_FORMAT_G729A 0x12
-#define DTE_FORMAT_UNDEF 0xFF
-
-#define G729_LENGTH 20
-#define G723_LENGTH 30
+#include "dahdi/kernel.h"
-#define G729_SAMPLES 160 /* G.729 */
-#define G723_SAMPLES 240 /* G.723.1 */
+/* COMPILE TIME OPTIONS =================================================== */
-#define G729_BYTES 20 /* G.729 */
-#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
-#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
-#define G723_SID_BYTES 4 /* G.723.1 SID frame */
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET 2
-#define ACK_SPACE 20
-
-#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
-#define MAX_RCV_COMMANDS 16
-
-/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
-#define BOOT_CMD_LEN 1500
-#define OTHER_CMD_LEN 300
-
-#define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */
-
-#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
-
-#define SFRAME_SIZE MAX_COMMAND_LEN
-
-#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+#ifndef DEFERRED_PROCESSING
+# define DEFERRED_PROCESSING WORKQUEUE
+#endif
-#define MDIO_SHIFT_CLK 0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB 0x00000
-#define MDIO_ENB_IN 0x40000
-#define MDIO_DATA_READ 0x80000
+#if DEFERRED_PROCESSING == INTERRUPT
+# define ALLOC_FLAGS GFP_ATOMIC
+#elif DEFERRED_PROCESSING == TASKLET
+# define ALLOC_FLAGS GFP_ATOMIC
+#else
+# define ALLOC_FLAGS GFP_KERNEL
+#endif
-#define RCV_CSMENCAPS 1
-#define RCV_RTP 2
-#define RCV_CSMENCAPS_ACK 3
-#define RCV_OTHER 99
+#define WARN() WARN_ON(1)
+
+#define DTE_PRINTK(_lvl, _fmt, _args...) \
+ printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args)
+
+#define DTE_DEBUG(_dbgmask, _fmt, _args...) \
+ if ((debug & _dbgmask) == (_dbgmask)) { \
+ printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args); \
+ } \
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define WARN_ON_ONCE(__condition) do { \
+ static int __once = 1; \
+ if (unlikely(__condition)) { \
+ if (__once) { \
+ __once = 0; \
+ WARN_ON(0); \
+ } \
+ } \
+} while(0)
+#endif
+#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
+#define MAX_CHANNEL_PACKETS 5 /* Never let more than 5 outstanding packets exist for any channel. */
+
+#define G729_LENGTH 20
+#define G723_LENGTH 30
+
+#define G729_SAMPLES 160 /* G.729 */
+#define G723_SAMPLES 240 /* G.723.1 */
+
+#define G729_BYTES 20 /* G.729 */
+#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
+#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
+#define G723_SID_BYTES 4 /* G.723.1 SID frame */
+
+#define MAX_CAPTURED_PACKETS 5000
+
+/* The following bit fields are used to set the various debug levels. */
+#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */
+#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */
+#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */
+#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */
+#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */
+#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */
+#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */
+
+int debug;
+char *mode;
+
+static spinlock_t wctc4xxp_list_lock;
+static struct list_head wctc4xxp_list;
+
+#define ETH_P_CSM_ENCAPS 0x889B
+
+struct rtphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 csrc_count:4;
+ __u8 extension:1;
+ __u8 padding:1;
+ __u8 ver:2;
+ __u8 type:7;
+ __u8 marker:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver:2;
+ __u8 padding:1;
+ __u8 extension:1;
+ __u8 csrc_count:4;
+ __u8 marker:1;
+ __u8 type:7;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __be16 seqno;
+ __be32 timestamp;
+ __be32 ssrc;
+} __attribute__((packed));
+
+struct rtp_packet {
+ struct ethhdr ethhdr;
+ struct iphdr iphdr;
+ struct udphdr udphdr;
+ struct rtphdr rtphdr;
+ __u8 payload[0];
+}__attribute__((packed));
+
+/* Ethernet packet type for communication control information to the DTE. */
+struct csm_encaps_hdr {
+ struct ethhdr ethhdr;
+ /* CSM_ENCAPS HEADER */
+ __be16 op_code;
+ __u8 seq_num;
+ __u8 control;
+ __be16 channel;
+ /* COMMON PART OF PAYLOAD HEADER */
+ __u8 length;
+ __u8 index;
+ __u8 type;
+ __u8 class;
+ __le16 function;
+ __le16 reserved;
+ __le16 params[0];
+} __attribute__((packed));
+
+struct csm_create_channel_cmd {
+ struct csm_encaps_hdr hdr;
+ __le16 channel_type;
+ __le16 timeslot;
+} __attribute__((packed));
-/* TDM Commands */
#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30
#define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -182,17 +248,26 @@
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \
0x02,0x00 }
-/* Supervisor channel commands */
-#define CMD_MSG_CREATE_CHANNEL_LEN 32
-#define CMD_MSG_CREATE_CHANNEL(s,t) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \
- 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) }
+#define CONTROL_PACKET_OPCODE 0x0001
+/* Control bits */
+#define LITTLE_ENDIAN 0x01
+#define SUPPRESS_ACK 0x40
+#define MESSAGE_PACKET 0x80
+
+#define SUPERVISOR_CHANNEL 0xffff
+
+/* Supervisor function codes */
+#define SUPVSR_CREATE_CHANNEL 0x0010
+
+#define CONFIG_CHANGE_TYPE 0x00
+#define CONFIG_DEVICE_CLASS 0x06
+
#define CMD_MSG_QUERY_CHANNEL_LEN 30
#define CMD_MSG_QUERY_CHANNEL(s,t) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \
(t&0x00FF), ((t&0xFF00) >> 8) }
+
#define CMD_MSG_TRANS_CONNECT_LEN 38
#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -243,1120 +318,1935 @@
0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \
0x00,0x00, 0x00,0x00 }
-/* CPU ACK command */
-#define CMD_MSG_ACK_LEN 20
-#define CMD_MSG_ACK(s,c) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) }
-
-/* Wrapper for RTP packets */
-#define CMD_MSG_IP_UDP_RTP_LEN 54
-#define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, \
- 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, \
- 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, \
- 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,(s&0xFF)}
-
-#define CMD_MSG_DW_WRITE_LEN 38
-#define CMD_MSG_DW_WRITE(s,a,d) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01,s&0x0F,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x00,0x00, \
- ((a>>24)&0x00FF),((a>>16)&0x00FF), ((a>>8)&0x00FF),(a&0x00FF), \
- ((d>>24)&0x00FF),((d>>16)&0x00FF), ((d>>8)&0x00FF),(d&0x00FF) }
+#define SFRAME_SIZE 320
+
+/* Transcoder buffer (tcb) */
+struct tcb {
+ /* First field so that is aligned by default. */
+ u8 cmd[SFRAME_SIZE];
+ struct list_head node;
+ unsigned long timeout;
+ unsigned long retries;
+ /* NOTE: these flags aren't bit fields because some of the flags are
+ * combinations of the other ones. */
+#define DO_NOT_AUTO_FREE (1 << 0)
+#define TX_COMPLETE (1 << 1)
+#define DO_NOT_CAPTURE (1 << 2)
+#define __WAIT_FOR_ACK (1 << 3)
+#define __WAIT_FOR_RESPONSE (1 << 4)
+#define DTE_CMD_TIMEOUT (1 << 5)
+#define WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE)
+#define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE)
+ unsigned long flags;
+ struct tcb *response;
+ struct completion complete;
+ struct timer_list timer;
+ void *data;
+ /* The number of bytes available in data. */
+ int data_len;
+};
-#define CMD_MSG_FORCE_ALERT_LEN 32
-#define CMD_MSG_FORCE_ALERT(s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x09,0x04, 0x00,0x00, \
- 0x24,0x00, 0x00,0x00 }
-
-#define dahdi_send_cmd(wc, command, length, hex) \
- ({ \
- int ret = 0; \
- do { \
- if (ret == 2) \
- { \
- wc->ztsnd_rtx++; \
- if (hex == 0x0010) \
- wc->ztsnd_0010_rtx++; \
- } \
- down(&wc->cmdqsem); \
- wc->last_command_sent = hex; \
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \
- printk(KERN_NOTICE "wcdte error: cmdq is full.\n"); \
- else { \
- unsigned char fifo[OTHER_CMD_LEN] = command; \
- int i; \
- wc->cmdq[wc->cmdq_wndx].cmdlen = length; \
- for (i = 0; i < length; i++) \
- wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \
- wc->last_seqno = fifo[16]; \
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
- } \
- __transmit_demand(wc); \
- up(&wc->cmdqsem); \
- if (hex == 0x0000) \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2); \
- else { \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
- if (wc->dsp_crashed) \
- return 1; \
- } \
- if (ret == 1) \
- return(1); \
- } while (ret == 2); \
- })
-
-
-struct cmdq {
- unsigned int cmdlen;
- unsigned char cmd[MAX_COMMAND_LEN];
+static inline void *hdr_from_cmd(struct tcb *cmd) {
+ return cmd->data;
+}
+
+static inline void
+initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ INIT_LIST_HEAD(&cmd->node);
+ init_completion(&cmd->complete);
+ cmd->flags = cmd_flags;
+ cmd->data = &cmd->cmd[0];
+ cmd->data_len = SFRAME_SIZE;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/*! Used to allocate commands to submit to the dte. */
+kmem_cache_t *cmd_cache;
+#else
+/*! Used to allocate commands to submit to the dte. */
+struct kmem_cache *cmd_cache;
+#endif
+
+static inline struct tcb *
+__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags)
+{
+ struct tcb *cmd;
+
+ cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
+ if (likely(cmd)) {
+ initialize_cmd(cmd, cmd_flags);
+ }
+ return cmd;
+}
+
+static struct tcb *
+alloc_cmd(void)
+{
+ return __alloc_cmd(GFP_KERNEL, 0);
+}
+
+static void
+__free_cmd(struct tcb *cmd)
+{
+ if (cmd->data != &cmd->cmd[0]) {
+ kfree(cmd->data);
+ }
+ kmem_cache_free(cmd_cache, cmd);
+ return;
+}
+
+static void
+free_cmd(struct tcb *cmd)
+{
+ if (cmd->response) {
+ __free_cmd(cmd->response);
+ }
+ __free_cmd(cmd);
+}
+
+typedef enum { DECODER=0, ENCODER, } encode_t;
+
+struct channel_stats {
+ atomic_t packets_sent;
+ atomic_t packets_received;
+};
+
+struct channel_pvt {
+ spinlock_t lock; /* Lock for this structure */
+ encode_t encoder; /* If we're an encoder */
+ struct wcdte *wc;
+
+ unsigned int timestamp;
+ unsigned int seqno;
+
+ unsigned int cmd_seqno;
+
+ unsigned int timeslot_in_num; /* DTE channel on which results will be received from */
+ unsigned int timeslot_out_num; /* DTE channel to send data to */
+
+ unsigned int chan_in_num; /* DTE channel on which results will be received from */
+ unsigned int chan_out_num; /* DTE channel to send data to */
+
+ struct channel_stats stats;
+
+ u16 last_dte_seqno;
+ unsigned int wctc4xxp_seqno_rcv;
+
+ unsigned char ssrc;
+ struct list_head rx_queue; /* Transcoded packets for this channel. */
};
struct wcdte {
- struct pci_dev *dev;
- char *variety;
- unsigned int intcount;
- unsigned int rxints;
- unsigned int txints;
- unsigned int intmask;
+ char board_name[40];
+ const char *variety;
int pos;
- int freeregion;
- int rdbl;
- int tdbl;
int cards;
+ struct list_head node;
spinlock_t reglock;
- wait_queue_head_t regq;
- int rcvflags;
-
+ wait_queue_head_t waitq;
struct semaphore chansem;
- struct semaphore cmdqsem;
- struct cmdq cmdq[MAX_COMMANDS];
- unsigned int cmdq_wndx;
- unsigned int cmdq_rndx;
-
- unsigned int last_seqno;
- unsigned int last_rseqno;
- unsigned int last_command_sent;
- unsigned int last_rcommand;
- unsigned int last_rparm1;
- unsigned int seq_num;
- long timeout;
-
- unsigned int dsp_crashed;
- unsigned int dumping;
+#define DTE_READY 1
+#define DTE_SHUTDOWN 2
+ unsigned long flags;
- unsigned int ztsnd_rtx;
- unsigned int ztsnd_0010_rtx;
+ spinlock_t cmd_list_lock;
+ /* This is a device-global list of commands that are waiting to be
+ * transmited (and did not fit on the transmit descriptor ring) */
+ struct list_head cmd_list;
+ struct list_head waiting_for_response_list;
+ unsigned int seq_num;
unsigned char numchannels;
unsigned char complexname[40];
- unsigned long iobase;
- dma_addr_t readdma;
- dma_addr_t writedma;
- dma_addr_t descripdma;
- volatile unsigned int *writechunk; /* Double-word aligned write memory */
- volatile unsigned int *readchunk; /* Double-word aligned read memory */
- volatile unsigned int *descripchunk; /* Descriptors */
+ /* This section contains the members necessary to communicate with the
+ * physical interface to the transcoding engine. */
+ struct pci_dev *pdev;
+ unsigned int intmask;
+ unsigned long iobase;
+ struct wctc4xxp_descriptor_ring *txd;
+ struct wctc4xxp_descriptor_ring *rxd;
- int wqueints;
- struct workqueue_struct *dte_wq;
- struct work_struct dte_work;
-
struct dahdi_transcoder *uencode;
struct dahdi_transcoder *udecode;
-};
+ struct channel_pvt *encoders;
+ struct channel_pvt *decoders;
+
+#if DEFERRED_PROCESSING == WORKQUEUE
+ struct work_struct deferred_work;
+#endif
+
+ /*
+ * This section contains the members necessary for exporting the
+ * network interface to the host system. This is only used for
+ * debugging purposes.
+ *
+ */
+ struct sk_buff_head captured_packets;
+ struct net_device *netdev;
+ struct net_device_stats net_stats;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ struct napi_struct napi;
+#endif
+ struct timer_list watchdog;
-struct wcdte_desc {
- char *name;
- int flags;
};
-static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 };
-static struct wcdte_desc wctce400 = { "Wildcard TCE400+TC400M", 0 };
+static inline void wctc4xxp_set_ready(struct wcdte *wc) {
+ set_bit(DTE_READY, &wc->flags);
+}
+static inline int wctc4xxp_is_ready(struct wcdte *wc) {
+ return test_bit(DTE_READY, &wc->flags);
+}
-static struct wcdte *ifaces[WC_MAX_IFACES];
+#if 1
+ /* \todo This macro is a candidate for removal. It's still here because of
+ * how the commands are passed to this dahdi_send_cmd */
+#define wctc4xxp_send_cmd(wc, command) ({ \
+ int __res; \
+ u8 _cmd[] = command; \
+ struct tcb *cmd; \
+ if (!(cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \
+ return -ENOMEM; \
+ BUG_ON(sizeof(_cmd) > SFRAME_SIZE); \
+ memcpy(cmd->data, _cmd, sizeof(_cmd)); \
+ cmd->data_len = sizeof(_cmd); \
+ __res = __wctc4xxp_send_cmd(wc, cmd); \
+ __res; \
+})
+#define wctc4xxp_create_cmd(wc, command) ({ \
+ u8 _command[] = command; \
+ struct tcb *_cmd; \
+ if (!(_cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \
+ return -ENOMEM; \
+ BUG_ON(sizeof(_command) > SFRAME_SIZE); \
+ memcpy(_cmd->data, _command, sizeof(_command)); \
+ _cmd->data_len = sizeof(_command); \
+ _cmd; \
+})
+#endif
+#define DTE_FORMAT_ULAW 0x00
+#define DTE_FORMAT_G723_1 0x04
+#define DTE_FORMAT_ALAW 0x08
+#define DTE_FORMAT_G729A 0x12
+#define DTE_FORMAT_UNDEF 0xFF
+static inline u8 wctc4xxp_dahdifmt_to_dtefmt(unsigned int fmt)
+{
+ u8 pt;
+
+ switch(fmt) {
+ case DAHDI_FORMAT_G723_1:
+ pt = DTE_FORMAT_G723_1;
+ break;
+ case DAHDI_FORMAT_ULAW:
+ pt = DTE_FORMAT_ULAW;
+ break;
+ case DAHDI_FORMAT_ALAW:
+ pt = DTE_FORMAT_ALAW;
+ break;
+ case DAHDI_FORMAT_G729A:
+ pt = DTE_FORMAT_G729A;
+ break;
+ default:
+ pt = DTE_FORMAT_UNDEF;
+ break;
+ }
-/*
- * The following is the definition of the state structure
- * used by the G.721/G.723 encoder and decoder to preserve their internal
- * state between successive calls. The meanings of the majority
- * of the state structure fields are explained in detail in the
- * CCITT Recommendation G.721. The field names are essentially indentical
- * to variable names in the bit level description of the coding algorithm
- * included in this Recommendation.
+ return pt;
+}
+
+
+static struct sk_buff *
+tcb_to_skb(struct net_device *netdev, const struct tcb *cmd)
+{
+ struct sk_buff *skb;
+ skb = alloc_skb(cmd->data_len, in_atomic() ? GFP_ATOMIC : GFP_KERNEL);
+ if (skb) {
+ skb->dev = netdev;
+ skb_put(skb, cmd->data_len);
+ memcpy(skb->data, cmd->data, cmd->data_len);
+ skb->protocol = eth_type_trans(skb,netdev);
+ }
+ return skb;
+}
+
+/**
+ * wctc4xxp_skb_to_cmd - Convert a socket buffer (skb) to a tcb
+ * @wc: The transcoder that we're going to send this command to.
+ * @skb: socket buffer to convert.
+ *
*/
-struct dte_state {
- int encoder; /* If we're an encoder */
- struct wcdte *wc;
+static struct tcb *
+wctc4xxp_skb_to_cmd(struct wcdte *wc, const struct sk_buff *skb)
+{
+ const unsigned long alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ struct tcb *cmd;
+ /* const static char dev_mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; */
+ if ((cmd = __alloc_cmd(alloc_flags, 0))) {
+ int res;
+ cmd->data_len = skb->len;
+ if ((res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len))) {
+ DTE_PRINTK(WARNING,
+ "Failed call to skb_copy_bits.\n");
+ free_cmd(cmd);
+ cmd = NULL;
+ }
+ /* When we set up our interface we indicated that we do not
+ * support ARP. Therefore, the destination MAC on packets
+ * arriving from the kernel networking components are not
+ * going to be correct. Let's fix that here.
+ */
+ /* \todo let us just use whatever was in the packet already... */
+ /* memcpy(&cmd->cmd[6], dev_mac, sizeof(dev_mac)); */
+ }
+ return cmd;
+}
- unsigned int timestamp;
- unsigned int seqno;
+static void
+wctc4xxp_net_set_multi(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n",
+ __FUNCTION__, netdev->promiscuity);
+}
- unsigned int cmd_seqno;
+static int
+wctc4xxp_net_up(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_poll_enable(netdev);
+#else
+ napi_enable(&wc->napi);
+#endif
+#endif
+ return 0;
+}
- unsigned int timeslot_in_num; /* DTE chennel on which results we be received from */
- unsigned int timeslot_out_num; /* DTE channel to send data to */
+static int
+wctc4xxp_net_down(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_poll_disable(netdev);
+#else
+ napi_disable(&wc->napi);
+#endif
+#endif
+ return 0;
+}
- unsigned int chan_in_num; /* DTE chennel on which results we be received from */
- unsigned int chan_out_num; /* DTE channel to send data to */
-
- unsigned int packets_sent;
- unsigned int packets_received;
+static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *);
- unsigned int last_dte_seqno;
- unsigned int dte_seqno_rcv;
+static int
+wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ struct tcb *cmd;
+
+ /* We set DO_NOT_CAPTURE because this packet was already captured by
+ * in code higher up in the networking stack. We don't want to
+ * capture it twice.
+ */
+ if ((cmd = wctc4xxp_skb_to_cmd(wc, skb))) {
+ cmd->flags |= DO_NOT_CAPTURE;
+ wctc4xxp_transmit_cmd(wc, cmd);
+ }
- unsigned char ssrc;
-};
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+static int
+wctc4xxp_net_receive(struct wcdte *wc, int max)
+{
+ int count = 0;
+ struct sk_buff *skb;
+ WARN_ON(0 == max);
+ while ((skb = skb_dequeue(&wc->captured_packets))) {
+ netif_receive_skb(skb);
+ if (++count >= max) {
+ break;
+ }
+ }
+ return count;
+}
-static struct dahdi_transcoder *uencode;
-static struct dahdi_transcoder *udecode;
-static struct dte_state *encoders;
-static struct dte_state *decoders;
-static int debug = 0;
-static int debug_des = 0; /* Set the number of descriptor packet bytes to output on errors, 0 disables output */
-static int debug_des_cnt = 0; /* Set the number of times descriptor packets are displayed before the output is disabled */
-static int force_alert = 0;
-static int debug_notimeout = 0;
-static char *mode;
-static int debug_packets = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int
+wctc4xxp_poll(struct net_device *netdev, int *budget)
+{
+ struct wcdte *wc = netdev->priv;
+ int count = 0;
+ int quota = min(netdev->quota, *budget);
-static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2);
-static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2);
-static int __wcdte_setup_channels(struct wcdte *wc);
+ count = wctc4xxp_net_receive(wc, quota);
-static int __dump_descriptors(struct wcdte *wc)
+ *budget -= count;
+ netdev->quota -= count;
+
+ if (!skb_queue_len(&wc->captured_packets)) {
+ netif_rx_complete(netdev);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+#else
+static int
+wctc4xxp_poll(struct napi_struct *napi, int budget)
{
- volatile unsigned char *writechunk, *readchunk;
- int o2, i, j;
+ struct wcdte *wc = container_of(napi, struct wcdte, napi);
+ int count;
- if (debug_des_cnt == 0)
- return 1;
+ count = wctc4xxp_net_receive(wc, budget);
- printk(KERN_DEBUG "Transmit Descriptors (wc->tdbl = %d)\n", wc->tdbl);
- for (i = 0; i < ERING_SIZE; i++)
- {
- writechunk = (volatile unsigned char *)(wc->writechunk);
- writechunk += i * SFRAME_SIZE;
- o2 = i * 4;
-
- if (i == wc->tdbl)
- printk(KERN_DEBUG "->");
- else
- printk(KERN_DEBUG " ");
- if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
- printk("AN983 owns : ");
- else
- printk("Driver owns: ");
-
- for (j = 0; j < debug_des; j++)
- printk("%02X ", writechunk[j]);
- printk("\n");
- }
-
- printk(KERN_DEBUG "Receive Descriptors (wc->rdbl = %d)\n", wc->rdbl);
- for (i = 0; i < ERING_SIZE; i++)
- {
- readchunk = (volatile unsigned char *)wc->readchunk;
- readchunk += i * SFRAME_SIZE;
- o2 = i * 4;
- o2 += ERING_SIZE * 4;
-
- if (i == wc->rdbl)
- printk(KERN_DEBUG "->");
- else
- printk(KERN_DEBUG " ");
- if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
- printk("AN983 owns : ");
- else
- printk("Driver owns: ");
-
- for (j = 0; j < debug_des; j++)
- printk("%02X ", readchunk[j]);
- printk("\n");
- }
- if (debug_des_cnt > 0)
- debug_des_cnt--;
+ if (!skb_queue_len(&wc->captured_packets)) {
+ netif_rx_complete(wc->netdev, &wc->napi);
+ }
+ return count;
+}
+#endif
+
+static struct net_device_stats *
+wctc4xxp_net_get_stats(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ return &wc->net_stats;
+}
+
+/* Wait until this device is put into promiscuous mode, or we timeout. */
+static void
+wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc)
+{
+ unsigned int seconds = 15;
+ unsigned long start = jiffies;
+ struct net_device *netdev = wc->netdev;
+
+ DTE_PRINTK(INFO,
+ "Waiting %d seconds for adapter to be placed in " \
+ "promiscuous mode for early trace.\n", seconds);
+
+ while (!netdev->promiscuity) {
+ if (signal_pending(current)) {
+ DTE_PRINTK(INFO,
+ "Aborting wait due to signal.\n");
+ break;
+ }
+ msleep(100);
+ if (time_after(jiffies, start + (seconds * HZ))) {
+ DTE_PRINTK(INFO,
+ "Aborting wait due to timeout.\n");
+ break;
+ }
+ }
+}
+
+static int wctc4xxp_turn_off_booted_led(struct wcdte *wc);
+static void wctc4xxp_turn_on_booted_led(struct wcdte *wc);
+
+static int
+wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct wcdte *wc = netdev->priv;
+ switch(cmd) {
+ case 0x89f0:
+ down(&wc->chansem);
+ wctc4xxp_turn_off_booted_led(wc);
+ break;
+ case 0x89f1:
+ wctc4xxp_turn_on_booted_led(wc);
+ up(&wc->chansem);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ };
return 0;
}
-/* Sanity check values */
-static inline int dahdi_tc_sanitycheck(struct dahdi_transcode_header *zth, unsigned int outbytes)
+/**
+ * wctc4xxp_net_register - Register a new network interface.
+ * @wc: transcoder card to register the interface for.
+ *
+ * The network interface is primarily used for debugging in order to watch the
+ * traffic between the transcoder and the host.
+ *
+ */
+static int
+wctc4xxp_net_register(struct wcdte *wc)
{
- if (zth->dstoffset >= sizeof(zth->dstdata))
- return 0;
- if (zth->dstlen >= sizeof(zth->dstdata))
- return 0;
- if (outbytes >= sizeof(zth->dstdata))
- return 0;
- if ((zth->dstoffset + zth->dstlen + outbytes) >= sizeof(zth->dstdata))
- return 0;
- if (zth->srcoffset >= sizeof(zth->srcdata))
- return 0;
- if (zth->srclen >= sizeof(zth->srcdata))
- return 0;
- if ((zth->srcoffset + zth->srclen) > sizeof(zth->srcdata))
- return 0;
- return 1;
+ int res;
+ struct net_device *netdev;
+ const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+
+ if (!(netdev = alloc_netdev(0, wc->board_name, ether_setup))) {
+ return -ENOMEM;
+ }
+
+ memcpy(netdev->dev_addr, our_mac, sizeof(our_mac));
+ netdev->priv = wc;
+ netdev->set_multicast_list = &wctc4xxp_net_set_multi;
+ netdev->open = &wctc4xxp_net_up;
+ netdev->stop = &wctc4xxp_net_down;
+ netdev->hard_start_xmit = &wctc4xxp_net_hard_start_xmit;
+ netdev->get_stats = &wctc4xxp_net_get_stats;
+ netdev->do_ioctl = &wctc4xxp_net_ioctl;
+ netdev->promiscuity = 0;
+ netdev->flags |= IFF_NOARP;
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netdev->poll = &wctc4xxp_poll;
+ netdev->weight = 64;
+# else
+ netif_napi_add(netdev, &wc->napi, &wctc4xxp_poll, 64);
+# endif
+
+ if ((res = register_netdev(netdev))) {
+ DTE_PRINTK(WARNING,
+ "Failed to register network device %s.\n",
+ wc->board_name);
+ goto error_sw;
+ }
+
+ wc->netdev = netdev;
+ skb_queue_head_init(&wc->captured_packets);
+
+ if (debug & DTE_DEBUG_NETWORK_EARLY) {
+ wctc4xxp_net_waitfor_promiscuous(wc);
+ }
+
+ DTE_PRINTK(DEBUG,
+ "Created network device %s for debug.\n", wc->board_name);
+ return 0;
+
+error_sw:
+ if (netdev) free_netdev(netdev);
+ return res;
}
-static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc)
+static void
+wctc4xxp_net_unregister(struct wcdte *wc)
{
- state_ptr->encoder = encoder;
- state_ptr->wc = wc;
- state_ptr->timestamp = 0;
- state_ptr->seqno = 0;
+ struct sk_buff *skb;
+ if (!wc->netdev) {
+ return;
+ }
+
+ unregister_netdev(wc->netdev);
+
+ while ((skb = skb_dequeue(&wc->captured_packets))) {
+ kfree_skb(skb);
+ }
+
+ free_netdev(wc->netdev);
+ wc->netdev = NULL;
+}
- state_ptr->cmd_seqno = 0;
- state_ptr->packets_sent = 0;
- state_ptr->packets_received = 0;
- state_ptr->last_dte_seqno = 0;
- state_ptr->dte_seqno_rcv = 0;
+/**
+ * wctc4xxp_net_capture_cmd - Send a tcb to the network stack.
+ * @wc: transcoder that received the command.
+ * @cmd: command to send to network stack.
+ *
+ */
+static void
+wctc4xxp_net_capture_cmd(struct wcdte *wc, const struct tcb *cmd)
+{
+ struct sk_buff *skb;
+ struct net_device *netdev = wc->netdev;
- state_ptr->chan_in_num = 999;
- state_ptr->chan_out_num = 999;
+ if (!netdev) {
+ return;
+ }
- state_ptr->ssrc = 0x78;
+ /* No need to capture if there isn't anyone listening. */
+ if (!(netdev->flags & IFF_UP)) {
+ return;
+ }
- if (encoder == 1)
- {
- state_ptr->timeslot_in_num = channel * 2;
- state_ptr->timeslot_out_num = channel * 2 + 1;
- } else {
- state_ptr->timeslot_in_num = channel * 2 + 1;
- state_ptr->timeslot_out_num = channel * 2;
+ if (skb_queue_len(&wc->captured_packets) > MAX_CAPTURED_PACKETS) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+ if (!(skb = tcb_to_skb(netdev, cmd))) {
+ return;
}
+
+ skb_queue_tail(&wc->captured_packets, skb);
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_rx_schedule(netdev);
+# else
+ netif_rx_schedule(netdev, &wc->napi);
+# endif
+ return;
}
-static unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt)
+
+/*! In-memory structure shared by the host and the adapter. */
+struct wctc4xxp_descriptor {
+ __le32 des0;
+ __le32 des1;
+ __le32 buffer1;
+ __le32 container; /* Unused */
+} __attribute__((packed));
+
+#define DRING_SIZE (1 << 3) /* Must be a power of two */
+#define DRING_MASK (DRING_SIZE-1)
+#define MIN_PACKET_LEN 64
+
+struct wctc4xxp_descriptor_ring {
+ /* Pointer to an array of descriptors to give to hardware. */
+ struct wctc4xxp_descriptor* desc;
+ /* Read completed buffers from the head. */
+ unsigned int head;
+ /* Write ready buffers to the tail. */
+ unsigned int tail;
+ /* Array to save the kernel virtual address of pending commands. */
+ struct tcb *pending[DRING_SIZE];
+ /* PCI Bus address of the descriptor list. */
+ dma_addr_t desc_dma;
+ /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
+ unsigned int direction;
+ /*! The number of buffers currently submitted to the hardware. */
+ unsigned int count;
+ /*! The number of bytes to pad each descriptor for cache alignment. */
+ unsigned int padding;
+ /*! Protects this structure from concurrent access. */
+ spinlock_t lock;
+ /*! PCI device for the card associated with this ring. */
+ struct pci_dev *pdev;
+};
+
+/**
+ * wctc4xxp_descriptor - Returns the desriptor at index.
+ * @dr: The descriptor ring we're using.
+ * @index: index of the descriptor we want.
+ *
+ * We need this function because we do not know what the padding on the
+ * descriptors will be. Otherwise, we would just use an array.
+ */
+static inline struct wctc4xxp_descriptor *
+wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index)
{
- unsigned int pt;
-
- switch(fmt)
+ return (struct wctc4xxp_descriptor *)((u8*)dr->desc +
+ ((sizeof(*dr->desc) + dr->padding) * index));
+}
+
+static int
+wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descriptor_ring *dr,
+ u32 des1, unsigned int direction)
+{
+ int i;
+ const u32 END_OF_RING = 0x02000000;
+ u8 cache_line_size = 0;
+ struct wctc4xxp_descriptor *d;
+
+ BUG_ON(!pdev);
+ BUG_ON(!dr);
+
+ if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) {
+ /* \todo Print an error message... */
+ return -EIO;
+ }
+
+ memset(dr, 0, sizeof(*dr));
+
+ /*
+ * Add some padding to each descriptor to ensure that they are
+ * aligned on host system cache-line boundaries, but only for the
+ * cache-line sizes that we support.
+ *
+ */
+ if ((0x08 == cache_line_size) || (0x10 == cache_line_size) ||
+ (0x20 == cache_line_size))
{
- case DAHDI_FORMAT_G723_1:
- pt = DTE_FORMAT_G723_1;
- break;
- case DAHDI_FORMAT_ULAW:
- pt = DTE_FORMAT_ULAW;
- break;
- case DAHDI_FORMAT_ALAW:
- pt = DTE_FORMAT_ALAW;
- break;
- case DAHDI_FORMAT_G729A:
- pt = DTE_FORMAT_G729A;
- break;
- default:
- pt = DTE_FORMAT_UNDEF;
+ dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d);
+ }
+
+ dr->desc = pci_alloc_consistent(pdev,
+ (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma);
+
+ if (!dr->desc) {
+ return -ENOMEM;
+ }
+
+ memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = wctc4xxp_descriptor(dr, i);
+ d->des1 = cpu_to_le32(des1);
}
- return(pt);
+ d->des1 |= cpu_to_le32(END_OF_RING);
+ dr->direction = direction;
+ spin_lock_init(&dr->lock);
+ return 0;
+}
+
+#define OWN_BIT cpu_to_le32(0x80000000)
+#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
+#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb();} while (0)
+
+const unsigned int BUFFER1_SIZE_MASK = 0x7ff;
+
+static int
+wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c)
+{
+ volatile struct wctc4xxp_descriptor *d;
+ unsigned int len;
+
+ WARN_ON(!c);
+ len = (c->data_len < MIN_PACKET_LEN) ? MIN_PACKET_LEN : c->data_len;
+ if (c->data_len > 1518) {
+ WARN_ON_ONCE(!"Invalid command length passed\n");
+ c->data_len = 1518;
+ }
+
+ spin_lock_bh(&dr->lock);
+ d = wctc4xxp_descriptor(dr, dr->tail);
+ WARN_ON(!d);
+ if (d->buffer1) {
+ spin_unlock_bh(&dr->lock);
+ /* Do not overwrite a buffer that is still in progress. */
+ return -EBUSY;
+ }
+ d->des1 &= cpu_to_le32(~(BUFFER1_SIZE_MASK));
+ d->des1 |= cpu_to_le32(len & BUFFER1_SIZE_MASK);
+ d->buffer1 = pci_map_single(dr->pdev, c->data,
+ SFRAME_SIZE, dr->direction);
+
+ SET_OWNED(d); /* That's it until the hardware is done with it. */
+ dr->pending[dr->tail] = c;
+ dr->tail = ++dr->tail & DRING_MASK;
+ ++dr->count;
+ spin_unlock_bh(&dr->lock);
+ return 0;
}
-static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+static inline struct tcb*
+wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr)
+{
+ volatile struct wctc4xxp_descriptor *d;
+ struct tcb *c;
+ unsigned int head = dr->head;
+ spin_lock_bh(&dr->lock);
+ d = wctc4xxp_descriptor(dr, head);
+ if (d->buffer1 && !OWNED(d)) {
+ pci_unmap_single(dr->pdev, d->buffer1,
+ SFRAME_SIZE, dr->direction);
+ c = dr->pending[head];
+ WARN_ON(!c);
+ dr->head = (++head) & DRING_MASK;
+ d->buffer1 = 0;
+ --dr->count;
+ WARN_ON(!c);
+ c->data_len = (d->des0 >> 16) & BUFFER1_SIZE_MASK;
+ c->flags |= TX_COMPLETE;
+ } else {
+ c = NULL;
+ }
+ spin_unlock_bh(&dr->lock);
+ return c;
+}
+
+static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr)
+{
+ int count;
+ spin_lock_bh(&dr->lock);
+ count = dr->count;
+ spin_unlock_bh(&dr->lock);
+ return count;
+}
+
+static inline void
+__wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
{
outl(val, wc->iobase + addr);
}
-static inline unsigned int __wcdte_getctl(struct wcdte *wc, unsigned int addr)
+static inline unsigned int
+__wctc4xxp_getctl(struct wcdte *wc, unsigned int addr)
{
return inl(wc->iobase + addr);
}
-static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+static inline void
+wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
{
- unsigned long flags;
- spin_lock_irqsave(&wc->reglock, flags);
- __wcdte_setctl(wc, addr, val);
- spin_unlock_irqrestore(&wc->reglock, flags);
+ spin_lock_bh(&wc->reglock);
+ __wctc4xxp_setctl(wc, addr, val);
+ spin_unlock_bh(&wc->reglock);
}
-static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s)
+static inline void
+wctc4xxp_receive_demand_poll(struct wcdte *wc)
{
- int o2 = 0;
- o2 += dbl * 4;
+ __wctc4xxp_setctl(wc, 0x0010, 0x00000000);
+}
- if (!tx)
- o2 += ERING_SIZE * 4;
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
+static inline void
+wctc4xxp_transmit_demand_poll(struct wcdte *wc)
+{
+ __wctc4xxp_setctl(wc, 0x0008, 0x00000000);
+
+ /* \todo Investigate why this register needs to be written twice in
+ * order to get it to poll reliably. So far, most of the problems
+ * I've seen with timeouts had more to do with an untransmitted
+ * packet sitting in the outbound descriptor list as opposed to any
+ * problem with the dte firmware.
+ */
+ __wctc4xxp_setctl(wc, 0x0008, 0x00000000);
+}
+
+/* Returns the size, in bytes, of a CSM_ENCAPS packet, given the number of
+ * parameters used. */
+#define SIZE_WITH_N_PARAMETERS(__n) (sizeof(struct csm_encaps_hdr) + ((__n) * (sizeof(u16))))
+
+/* There are 20 bytes in the ethernet header and the common CSM_ENCAPS header
+ * that we don't want in the length of the actual CSM_ENCAPS command */
+#define LENGTH_WITH_N_PARAMETERS(__n) (SIZE_WITH_N_PARAMETERS(__n) - 20)
- wcdte_setctl(wc, 0x0008, 0x00000000);
+static const u8 dst_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+static const u8 src_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
+
+static void
+setup_common_header(struct wcdte *wc, struct csm_encaps_hdr *hdr)
+{
+ memcpy(hdr->ethhdr.h_dest, dst_mac, sizeof(dst_mac));
+ memcpy(hdr->ethhdr.h_source, src_mac, sizeof(src_mac));
+ hdr->ethhdr.h_proto = cpu_to_be16(ETH_P_CSM_ENCAPS);
}
-static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr)
+static void
+setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr)
{
- unsigned long flags;
- unsigned int val;
- spin_lock_irqsave(&wc->reglock, flags);
- val = __wcdte_getctl(wc, addr);
- spin_unlock_irqrestore(&wc->reglock, flags);
- return val;
+ setup_common_header(wc, hdr);
+
+ hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE);
+ hdr->control = LITTLE_ENDIAN;
+ hdr->seq_num = (wc->seq_num++)&0xf;
+ hdr->channel = cpu_to_be16(SUPERVISOR_CHANNEL);
}
-static inline int __transmit_demand(struct wcdte *wc)
+static void
+__wctc4xxp_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot)
{
- volatile unsigned char *writechunk;
- int o2,i,j;
- unsigned int reg, xmt_length;
+ struct csm_create_channel_cmd *c;
+ c = hdr_from_cmd(cmd);
- reg = wcdte_getctl(wc, 0x0028) & 0x00700000;
-
- /* Already transmiting, no need to demand another */
- if (!((reg == 0) || (reg = 6)))
- return(1);
+ BUG_ON(timeslot > 0x01ff);
- /* Nothing to transmit */
- if (wc->cmdq_rndx == wc->cmdq_wndx)
- return(1);
+ setup_supervisor_header(wc, &c->hdr);
- /* Nothing to transmit */
- if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 )
- return(1);
+ c->hdr.length = LENGTH_WITH_N_PARAMETERS(2);
+ c->hdr.index = 0x0;
+ c->hdr.type = CONFIG_CHANGE_TYPE;
+ c->hdr.class = CONFIG_DEVICE_CLASS;
+ c->hdr.function = cpu_to_le16(SUPVSR_CREATE_CHANNEL);
+ c->hdr.reserved = 0x0000;
- writechunk = (volatile unsigned char *)(wc->writechunk);
+ c->channel_type = cpu_to_le16(0x0002); /* Channel type is VoIP */
+ c->timeslot = cpu_to_le16(timeslot);
- writechunk += wc->tdbl * SFRAME_SIZE;
+ cmd->flags |= WAIT_FOR_RESPONSE;
+ cmd->data_len = sizeof(*c);
+}
- o2 = wc->tdbl * 4;
+struct tcb *
+wctc4xxp_create_channel_cmd(struct wcdte *wc, u16 timeslot)
+{
+ struct tcb *cmd;
+ if (!(cmd = alloc_cmd())) {
+ return NULL;
+ }
+ __wctc4xxp_create_channel_cmd(wc, cmd, timeslot);
+ return cmd;
+}
- do
- {
- } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000));
+void
+__wctc4xxp_create_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+ struct csm_encaps_hdr *hdr = cmd->data;
+ BUG_ON(SIZE_WITH_N_PARAMETERS(2) > cmd->data_len);
+
+ setup_supervisor_header(wc, hdr);
+
+ hdr->length = LENGTH_WITH_N_PARAMETERS(2);
+ hdr->index = 0x0;
+ hdr->type = CONFIG_CHANGE_TYPE;
+ hdr->class = CONFIG_DEVICE_CLASS;
+ hdr->function = cpu_to_le16(0x0411);
+ hdr->reserved = 0x0000;
+ hdr->params[0] = cpu_to_le16(0x012c);
+ hdr->params[1] = cpu_to_le16(0x0000);
+
+ cmd->flags |= WAIT_FOR_RESPONSE;
+ cmd->data_len = SIZE_WITH_N_PARAMETERS(2);
+ return;
+}
- xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen;
- if (xmt_length < 64)
- xmt_length = 64;
-
- wc->descripchunk[o2+1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2+1]) & 0xFBFFF800) | xmt_length);
-
- for(i = 0; i < wc->cmdq[wc->cmdq_rndx].cmdlen; i++)
- writechunk[i] = wc->cmdq[wc->cmdq_rndx].cmd[i];
- for (j = i; j < xmt_length; j++)
- writechunk[j] = 0;
-
- if (debug_packets && (writechunk[12] == 0x88) && (writechunk[13] == 0x9B))
- {
- printk(KERN_DEBUG "wcdte debug: TX: ");
- for (i=0; i<debug_packets; i++)
- printk("%02X ", writechunk[i]);
- printk("\n");
+struct tcb *
+wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc, size_t inbytes)
+{
+ const struct channel_pvt *cpvt = dtc->pvt;
+ struct rtp_packet *packet;
+ struct tcb *cmd;
+
+ if (!(cmd = alloc_cmd())) {
+ return NULL;
}
- wc->cmdq[wc->cmdq_rndx].cmdlen = 0;
+ packet = cmd->data;
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
- wcdte_setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */
+ BUG_ON(cmd->data_len < sizeof(*packet));
+
+ /* setup the ethernet header */
+ memcpy(packet->ethhdr.h_dest, dst_mac, sizeof(dst_mac));
+ memcpy(packet->ethhdr.h_source, src_mac, sizeof(src_mac));
+ packet->ethhdr.h_proto = cpu_to_be16(ETH_P_IP);
+
+ /* setup the IP header */
+ packet->iphdr.ihl = 5;
+ packet->iphdr.version = 4;
+ packet->iphdr.tos = 0;
+ packet->iphdr.tot_len = cpu_to_be16(inbytes+40);
+ packet->iphdr.id = cpu_to_be16(cpvt->seqno);
+ packet->iphdr.frag_off= cpu_to_be16(0x4000);
+ packet->iphdr.ttl = 64;
+ packet->iphdr.protocol= 0x11; /* UDP */
+ packet->iphdr.check = 0;
+ packet->iphdr.saddr = cpu_to_be32(0xc0a80903);
+ packet->iphdr.daddr = cpu_to_be32(0xc0a80903);
+ packet->iphdr.check = ip_fast_csum((void*)&packet->iphdr, sizeof(struct iphdr));
+
+ /* setup the UDP header */
+ packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000);
+ packet->udphdr.dest = cpu_to_be16(cpvt->timeslot_in_num + 0x5000);
+ packet->udphdr.len = cpu_to_be16(inbytes + sizeof(struct rtphdr) + sizeof(struct udphdr));
+ packet->udphdr.check = 0;
+
+ /* Setup the RTP header */
+ packet->rtphdr.ver = 2;
+ packet->rtphdr.padding = 0;
+ packet->rtphdr.extension = 0;
+ packet->rtphdr.csrc_count = 0;
+ packet->rtphdr.marker = 0;
+ packet->rtphdr.type = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt);
+ packet->rtphdr.seqno = cpu_to_be16(cpvt->seqno);
+ packet->rtphdr.timestamp = cpu_to_be32(cpvt->timestamp);
+ packet->rtphdr.ssrc = cpu_to_be32(cpvt->ssrc);
+
+ cmd->data_len = sizeof(*packet) + inbytes;
+
+ return cmd;
+}
+static void
+wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
+{
+ int i;
+ struct wctc4xxp_descriptor *d;
- wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
+ /* NOTE: The DTE must be in the stopped state. */
+ spin_lock_bh(&dr->lock);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = wctc4xxp_descriptor(dr, i);
+ if (d->buffer1) {
+ dma_unmap_single(&dr->pdev->dev, d->buffer1,
+ SFRAME_SIZE, dr->direction);
+ d->buffer1 = 0;
+ /* Commands will also be sitting on the waiting for
+ * response list, so we want to make sure to delete
+ * them from that list as well. */
+ list_del_init(&(dr->pending[i])->node);
+ free_cmd(dr->pending[i]);
+ dr->pending[i] = NULL;
+ }
+ }
+ dr->head = 0;
+ dr->tail = 0;
+ dr->count = 0;
+ spin_unlock_bh(&dr->lock);
+ pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE,
+ dr->desc, dr->desc_dma);
+}
- wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS;
+static void wctc4xxp_cleanup_command_list(struct wcdte *wc)
+{
+ struct tcb *cmd;
+ LIST_HEAD(local_list);
+
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_splice_init(&wc->cmd_list, &local_list);
+ list_splice_init(&wc->waiting_for_response_list, &local_list);
+ spin_unlock_bh(&wc->cmd_list_lock);
+
+ while(!list_empty(&local_list)) {
+ cmd = list_entry(local_list.next, struct tcb, node);
+ list_del_init(&cmd->node);
+ free_cmd(cmd);
+ }
+}
- return(0);
+/**
+ * The command list is used to store commands that couldn't fit in the tx
+ * descriptor list when they were requested.
+ */
+static void
+wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd)
+{
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_add_tail(&cmd->node, &wc->cmd_list);
+ spin_unlock_bh(&wc->cmd_list_lock);
}
-static inline int transmit_demand(struct wcdte *wc)
+static void
+wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd)
{
- int val;
- down(&wc->cmdqsem);
- val = __transmit_demand(wc);
- up(&wc->cmdqsem);
- return val;
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_add_tail(&cmd->node, &wc->waiting_for_response_list);
+ spin_unlock_bh(&wc->cmd_list_lock);
}
-static int dte_operation(struct dahdi_transcoder_channel *ztc, int op)
-{
- struct dahdi_transcoder_channel *compl_ztc;
- struct dte_state *st = ztc->pvt, *compl_st;
- struct dahdi_transcode_header *zth = ztc->tch;
- struct wcdte *wc = st->wc;
- unsigned char *chars;
- unsigned int inbytes = 0;
- unsigned int timestamp_inc = 0;
- int i = 0;
- int res = 0;
- unsigned int ipchksum, ndx;
- switch(op) {
- case DAHDI_TCOP_ALLOCATE:
- down(&wc->chansem);
- if (ztc->chan_built == 0)
- {
- if (st->encoder == 1)
- wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->srcfmt), wcdte_zapfmt_to_dtefmt(zth->dstfmt),
- st->timeslot_in_num, st->timeslot_out_num, &(st->chan_in_num), &(st->chan_out_num));
- else
- wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->dstfmt), wcdte_zapfmt_to_dtefmt(zth->srcfmt),
- st->timeslot_out_num, st->timeslot_in_num, &(st->chan_out_num), &(st->chan_in_num));
- /* Mark this channel as built */
- ztc->chan_built = 1;
- ztc->built_fmts = zth->dstfmt | zth->srcfmt;
-
- /* Mark the channel complement (other half of encoder/decoder pair) as built */
- ndx = st->timeslot_in_num/2;
- if (st->encoder == 1)
- compl_ztc = &(wc->udecode->channels[ndx]);
- else
- compl_ztc = &(wc->uencode->channels[ndx]);
- compl_ztc->chan_built = 1;
- compl_ztc->built_fmts = zth->dstfmt | zth->srcfmt;
- compl_st = compl_ztc->pvt;
- compl_st->chan_in_num = st->chan_out_num;
- compl_st->chan_out_num = st->chan_in_num;
+static void
+wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd)
+{
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_del_init(&cmd->node);
+ spin_unlock_bh(&wc->cmd_list_lock);
+}
+
+static void
+wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+ int res;
+
+ if (cmd->data_len < MIN_PACKET_LEN) {
+ memset((u8*)(cmd->data) + cmd->data_len, 0,
+ MIN_PACKET_LEN-cmd->data_len);
+ cmd->data_len = MIN_PACKET_LEN;
+ }
+ WARN_ON(cmd->response);
+ WARN_ON(cmd->flags & TX_COMPLETE);
+ cmd->timeout = jiffies + HZ/4;
+ if (cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE)) {
+ if (cmd->flags & __WAIT_FOR_RESPONSE) {
+ /* We don't need both an ACK and a response. Let's
+ * tell the DTE not to generate an ACK, and we'll just
+ * retry if we do not get the response within the
+ * timeout period. */
+ struct csm_encaps_hdr *hdr = cmd->data;
+ hdr->control |= SUPPRESS_ACK;
}
- up(&wc->chansem);
- break;
- case DAHDI_TCOP_RELEASE:
- down(&wc->chansem);
- ndx = st->timeslot_in_num/2;
-
- if (st->encoder == 1)
- compl_ztc = &(wc->udecode->channels[ndx]);
- else
- compl_ztc = &(wc->uencode->channels[ndx]);
-
- /* If the channel complement (other half of the encoder/decoder pair) is not being used... */
- if ((compl_ztc->flags & DAHDI_TC_FLAG_BUSY) == 0)
- {
- if (st->encoder == 1)
- wcdte_destroy_channel(wc, st->chan_in_num, st->chan_out_num);
- else
- wcdte_destroy_channel(wc, st->chan_out_num, st->chan_in_num);
-
- /* Mark this channel as not built */
- ztc->chan_built = 0;
- ztc->built_fmts = 0;
- st->chan_in_num = 999;
- st->chan_out_num = 999;
-
- /* Mark the channel complement as not built */
- compl_ztc->chan_built = 0;
- compl_ztc->built_fmts = 0;
- compl_st = compl_ztc->pvt;
- compl_st->chan_in_num = 999;
- compl_st->chan_out_num = 999;
+ WARN_ON(!list_empty(&cmd->node));
+ wctc4xxp_add_to_response_list(wc, cmd);
+ mod_timer(&wc->watchdog, jiffies + HZ/2);
+ }
+ if (!(cmd->flags & DO_NOT_CAPTURE)) wctc4xxp_net_capture_cmd(wc, cmd);
+ if ((res=wctc4xxp_submit(wc->txd, cmd))) {
+ if (-EBUSY == res) {
+ /* Looks like we're out of room in the descriptor
+ * ring. We'll add this command to the pending list
+ * and the interrupt service routine will pull from
+ * this list as it clears up room in the descriptor
+ * ring. */
+ wctc4xxp_remove_from_response_list(wc, cmd);
+ wctc4xxp_add_to_command_list(wc, cmd);
+ } else {
+ /* Unknown return value... */
+ WARN_ON(1);
}
- st->dte_seqno_rcv = 0;
- up(&wc->chansem);
- break;
- case DAHDI_TCOP_TRANSCODE:
- if ( (((zth->srcfmt == DAHDI_FORMAT_ULAW) || (zth->srcfmt == DAHDI_FORMAT_ALAW)) && ((zth->dstfmt == DAHDI_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == DAHDI_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
- || ((zth->srcfmt == DAHDI_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
- || ((zth->srcfmt == DAHDI_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) )
- {
- do
- {
- chars = (unsigned char *)(zth->srcdata + zth->srcoffset);
-
- if ((zth->srcfmt == DAHDI_FORMAT_ULAW) || (zth->srcfmt == DAHDI_FORMAT_ALAW)) {
- if (zth->dstfmt == DAHDI_FORMAT_G729A) {
- inbytes = G729_SAMPLES;
- timestamp_inc = G729_SAMPLES;
- } else if (zth->dstfmt == DAHDI_FORMAT_G723_1) {
- inbytes = G723_SAMPLES;
- timestamp_inc = G723_SAMPLES;
- }
- } else if (zth->srcfmt == DAHDI_FORMAT_G729A) {
- inbytes = G729_BYTES;
- timestamp_inc = G729_SAMPLES;
- } else if (zth->srcfmt == DAHDI_FORMAT_G723_1) {
- /* determine the size of the frame */
- switch (chars[0] & 0x03) {
- case 0x00:
- inbytes = G723_6K_BYTES;
- break;
- case 0x01:
- inbytes = G723_5K_BYTES;
- break;
- case 0x02:
- inbytes = G723_SID_BYTES;
- break;
- case 0x03:
- /* this is a 'reserved' value in the G.723.1
- spec and should never occur in real media streams */
- inbytes = G723_SID_BYTES;
- break;
- }
- timestamp_inc = G723_SAMPLES;
- }
+ } else {
+ wctc4xxp_transmit_demand_poll(wc);
+ }
+}
- zth->srclen -= inbytes;
-
- {
- unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_IP_UDP_RTP(
- ((inbytes+40) >> 8) & 0xFF,
- (inbytes+40) & 0xFF,
- st->seqno & 0xFF,
- 0x00,
- 0x00,
- (((st->timeslot_out_num) >> 8)+0x50) & 0xFF,
- (st->timeslot_out_num) & 0xFF,
- (((st->timeslot_in_num) >> 8)+0x50) & 0xFF,
- (st->timeslot_in_num) & 0xFF,
- ((inbytes+20) >> 8) & 0xFF,
- (inbytes+20) & 0xFF,
- 0x00,
- 0x00,
- wcdte_zapfmt_to_dtefmt(zth->srcfmt),
- ((st->seqno) >> 8) & 0xFF,
- (st->seqno) & 0xFF,
- ((st->timestamp) >> 24) & 0xFF,
- ((st->timestamp) >> 16) & 0xFF,
- ((st->timestamp) >> 8) & 0xFF,
- (st->timestamp) & 0xFF,
- (st->ssrc) & 0xFF);
-
- ipchksum = 0x9869 + (fifo[16] << 8) + fifo[17]
- + (fifo[18] << 8) + fifo[19];
- while (ipchksum >> 16)
- ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16);
- ipchksum = (~ipchksum) & 0xFFFF;
-
- fifo[24] = ipchksum >> 8;
- fifo[25] = ipchksum & 0xFF;
-
- st->seqno += 1;
- st->timestamp += timestamp_inc;
-
- for (i = 0; i < inbytes; i++)
- fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i];
-
- down(&wc->cmdqsem);
-
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
- printk(KERN_NOTICE "wcdte error: cmdq is full.\n");
- else
- {
- wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_IP_UDP_RTP_LEN+inbytes;
- for (i = 0; i < CMD_MSG_IP_UDP_RTP_LEN+inbytes; i++)
- wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i];
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
- }
-
- __transmit_demand(wc);
- up(&wc->cmdqsem);
- }
- st->packets_sent++;
+static int
+wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd)
+{
+ cmd->flags |= DO_NOT_AUTO_FREE;
+ wctc4xxp_transmit_cmd(wc, cmd);
+ wait_for_completion(&cmd->complete);
+ if (cmd->flags & DTE_CMD_TIMEOUT) {
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n");
+ return -EIO;
+ }
+ return 0;
+}
+static int wctc4xxp_create_channel_pair(struct wcdte *wc,
+ struct channel_pvt *cpvt, u8 simple, u8 complicated);
+static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt);
+static int __wctc4xxp_setup_channels(struct wcdte *wc);
+static int
+__wctc4xxp_send_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+ int ret = 0;
+ wctc4xxp_transmit_cmd(wc, cmd);
+ wait_for_completion(&cmd->complete);
+ if (cmd->flags & DTE_CMD_TIMEOUT) {
+ ret = -EIO;
+ }
+ free_cmd(cmd);
+ return ret;
+}
- zth->srcoffset += inbytes;
+static void
+wctc4xxp_init_state(struct channel_pvt *cpvt, encode_t encoder,
+ unsigned int channel, struct wcdte *wc)
+{
+ memset(cpvt, 0, sizeof(*cpvt));
+ cpvt->encoder = encoder;
+ cpvt->wc = wc;
+ cpvt->chan_in_num = INVALID;
+ cpvt->chan_out_num = INVALID;
- } while ((((zth->srcfmt == DAHDI_FORMAT_ULAW) || (zth->srcfmt == DAHDI_FORMAT_ALAW)) && ((zth->dstfmt == DAHDI_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == DAHDI_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
- || ((zth->srcfmt == DAHDI_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
- || ((zth->srcfmt == DAHDI_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) );
+ cpvt->ssrc = 0x78;
+
+ cpvt->timeslot_in_num = channel* 2;
+ cpvt->timeslot_out_num = channel * 2;
- } else {
- dahdi_transcoder_alert(ztc);
- }
+ if (ENCODER == encoder) {
+ cpvt->timeslot_out_num++;
+ } else {
+ cpvt->timeslot_in_num++;
+ }
+ spin_lock_init(&cpvt->lock);
+ INIT_LIST_HEAD(&cpvt->rx_queue);
+}
- res = 0;
- break;
+static unsigned int
+wctc4xxp_getctl(struct wcdte *wc, unsigned int addr)
+{
+ unsigned int val;
+ spin_lock_bh(&wc->reglock);
+ val = __wctc4xxp_getctl(wc, addr);
+ spin_unlock_bh(&wc->reglock);
+ return val;
+}
+
+static void
+wctc4xxp_cleanup_channel_private(struct wcdte *wc, struct channel_pvt *cpvt)
+{
+ struct tcb *cmd, *temp;
+ LIST_HEAD(local_list);
+
+ spin_lock_bh(&cpvt->lock);
+ list_splice_init(&cpvt->rx_queue, &local_list);
+ spin_unlock_bh(&cpvt->lock);
+
+ list_for_each_entry_safe(cmd, temp, &local_list, node) {
+ list_del(&cmd->node);
+ free_cmd(cmd);
}
+}
+
+static int
+wctc4xxp_mark_channel_complement_built(struct wcdte *wc,
+ struct dahdi_transcoder_channel *dtc)
+{
+ int index;
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct dahdi_transcoder_channel *compl_dtc;
+ struct channel_pvt *compl_cpvt;
+
+ BUG_ON(!cpvt);
+ index = cpvt->timeslot_in_num/2;
+ BUG_ON(index >= wc->numchannels);
+ if (cpvt->encoder == 1) {
+ compl_dtc = &(wc->udecode->channels[index]);
+ } else {
+ compl_dtc = &(wc->uencode->channels[index]);
+ }
+
+ /* It shouldn't already have been built... */
+ WARN_ON(dahdi_tc_is_built(compl_dtc));
+ compl_dtc->built_fmts = dtc->dstfmt | dtc->srcfmt;
+ compl_cpvt = compl_dtc->pvt;
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "dtc: %p is the complement to %p\n", compl_dtc, dtc);
+ compl_cpvt->chan_in_num = cpvt->chan_out_num;
+ compl_cpvt->chan_out_num = cpvt->chan_in_num;
+ dahdi_tc_set_built(compl_dtc);
+ wctc4xxp_cleanup_channel_private(wc, compl_cpvt);
+
+ return 0;
+}
+
+static int
+do_channel_allocate(struct dahdi_transcoder_channel *dtc)
+{
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct wcdte *wc = cpvt->wc;
+ u8 wctc4xxp_srcfmt; /* Digium Transcoder Engine Source Format */
+ u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */
+ int res;
+
+ down(&wc->chansem);
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "Entering %s for channel %p.\n", __FUNCTION__, dtc);
+ /* Anything on the rx queue now is old news... */
+ dahdi_tc_clear_data_waiting(dtc);
+ wctc4xxp_cleanup_channel_private(wc, cpvt);
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating a new channel: %p.\n", dtc);
+ wctc4xxp_srcfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt);
+ wctc4xxp_dstfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->dstfmt);
+ res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt,
+ wctc4xxp_dstfmt);
+ if (res) {
+ /* There was a problem creating the channel.... */
+ up(&wc->chansem);
+ return res;
+ }
+ /* Mark this channel as built */
+ dahdi_tc_set_built(dtc);
+ dtc->built_fmts = dtc->dstfmt | dtc->srcfmt;
+ /* Mark the channel complement (other half of encoder/decoder pair) as built */
+ res = wctc4xxp_mark_channel_complement_built(wc, dtc);
+ up(&wc->chansem);
+ dahdi_transcoder_alert(dtc);
return res;
}
-static void wcdte_stop_dma(struct wcdte *wc);
+static int
+wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
+{
+ struct wcdte *wc = ((struct channel_pvt*)(dtc->pvt))->wc;
+
+ if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
+ /* The shudown flags can also be set if there is a
+ * catastrophic failure. */
+ return -EIO;
+ }
-static inline void wcdte_receiveprep(struct wcdte *wc, int dbl)
+ if (dahdi_tc_is_built(dtc)) {
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "Allocating channel %p which is already built.\n", dtc);
+ return 0;
+ }
+ return do_channel_allocate(dtc);
+}
+
+static int
+wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
{
- volatile unsigned char *readchunk;
- struct dahdi_transcoder_channel *ztc = NULL;
- struct dahdi_transcode_header *zth = NULL;
- struct dte_state *st = NULL;
- int o2,i;
- unsigned char rseq, rcodec;
- unsigned int rcommand, rchannel, rlen, rtp_rseq, rtp_eseq;
- unsigned char *chars = NULL;
- unsigned int ztc_ndx;
+ int res;
+ int index;
+ /* This is the 'complimentary channel' to dtc. I.e., if dtc is an
+ * encoder, compl_dtc is the decoder and vice-versa */
+ struct dahdi_transcoder_channel *compl_dtc;
+ struct channel_pvt *compl_cpvt;
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct wcdte *wc = cpvt->wc;
+
+ BUG_ON(!cpvt);
+ BUG_ON(!wc);
+
+ if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
+ /* The shudown flags can also be set if there is a
+ * catastrophic failure. */
+ return -EIO;
+ }
+
+ /* !!!SRR!!! change this back to down after troubleshooting */
+ if (down_interruptible(&wc->chansem)) {
+ return -EINTR;
+ }
+ /* Remove any packets that are waiting on the outbound queue. */
+ wctc4xxp_cleanup_channel_private(wc, cpvt);
+ index = cpvt->timeslot_in_num/2;
+ BUG_ON(index >= wc->numchannels);
+ if (ENCODER == cpvt->encoder) {
+ compl_dtc = &(wc->udecode->channels[index]);
+ } else {
+ compl_dtc = &(wc->uencode->channels[index]);
+ }
+ BUG_ON(!compl_dtc);
+ if (!dahdi_tc_is_built(compl_dtc)) {
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "Releasing a channel that was never built.\n");
+ res = 0;
+ goto error_exit;
+ }
+ /* If the channel complement (other half of the encoder/decoder pair) is
+ * being used... */
+ if (dahdi_tc_is_busy(compl_dtc)) {
+ res = -EBUSY;
+ goto error_exit;
+ }
+ if ((res = wctc4xxp_destroy_channel_pair(wc, cpvt))) {
+ goto error_exit;
+ }
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %p\n", dtc);
+ /* Mark this channel as not built */
+ dahdi_tc_clear_built(dtc);
+ dtc->built_fmts = 0;
+ cpvt->chan_in_num = INVALID;
+ cpvt->chan_out_num = INVALID;
+ /* Mark the channel complement as not built */
+ dahdi_tc_clear_built(compl_dtc);
+ compl_dtc->built_fmts = 0;
+ compl_cpvt = compl_dtc->pvt;
+ compl_cpvt->chan_in_num = INVALID;
+ compl_cpvt->chan_out_num = INVALID;
+ cpvt->wctc4xxp_seqno_rcv = 0;
+error_exit:
+ up(&wc->chansem);
+ return res;
+}
- readchunk = (volatile unsigned char *)wc->readchunk;
- readchunk += dbl * SFRAME_SIZE;
+static inline struct tcb*
+get_ready_cmd(struct dahdi_transcoder_channel *dtc)
+{
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct tcb *cmd;
+ spin_lock_bh(&cpvt->lock);
+ if (!list_empty(&cpvt->rx_queue)) {
+ WARN_ON(!dahdi_tc_is_data_waiting(dtc));
+ cmd = list_entry(cpvt->rx_queue.next, struct tcb, node);
+ list_del_init(&cmd->node);
+ } else {
+ cmd = NULL;
+ }
+ if (list_empty(&cpvt->rx_queue)) {
+ dahdi_tc_clear_data_waiting(dtc);
+ }
+ spin_unlock_bh(&cpvt->lock);
+ return cmd;
+}
- o2 = dbl * 4;
- o2 += ERING_SIZE * 4;
-
- /* Control in packet */
- if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B))
- {
- if (debug_packets)
- {
- printk(KERN_DEBUG "wcdte debug: RX: ");
- for (i=0; i<debug_packets; i++)
- printk("%02X ", readchunk[i]);
- printk("\n");
- }
- /* See if message must be ACK'd */
- if ((readchunk[17] & 0x80) == 0)
- {
- rcommand = readchunk[24] | (readchunk[25] << 8);
- rchannel = readchunk[18] | (readchunk[19] << 8);
- rseq = readchunk[16];
-
- down(&wc->cmdqsem);
- if ((readchunk[17] & 0x40) == 0) {
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
- printk(KERN_NOTICE "wcdte error: cmdq is full (rndx = %d, wndx = %d).\n", wc->cmdq_rndx, wc->cmdq_wndx);
- else
- {
- unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_ACK(rseq++, rchannel);
-
- wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_ACK_LEN;
- for (i = 0; i < wc->cmdq[wc->cmdq_wndx].cmdlen; i++)
- wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i];
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
- }
+/* Called with a buffer in which to copy a transcoded frame. */
+static ssize_t
+wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ struct dahdi_transcoder_channel *dtc = file->private_data;
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct wcdte *wc = cpvt->wc;
+ struct tcb *cmd;
+ struct rtp_packet *packet;
+ ssize_t payload_bytes;
+ u16 rtp_eseq;
+
+ BUG_ON(!dtc);
+ BUG_ON(!cpvt);
+
+ if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
+ /* The shudown flags can also be set if there is a
+ * catastrophic failure. */
+ return -EIO;
+ }
- __transmit_demand(wc);
- }
-
- wc->rcvflags = RCV_CSMENCAPS;
- if (rcommand == wc->last_command_sent) {
- wc->last_rcommand = rcommand;
- wc->last_rparm1 = readchunk[28] | (readchunk[29] << 8);
- wake_up(&wc->regq);
+ if (!(cmd = get_ready_cmd(dtc))) {
+ if (file->f_flags & O_NONBLOCK) {
+ return -EAGAIN;
+ } else {
+ ret = wait_event_interruptible(dtc->ready,
+ dahdi_tc_is_data_waiting(dtc));
+ if (-ERESTARTSYS == ret) {
+ /* Signal interrupted the wait */
+ return -EINTR;
} else {
- if (debug)
- printk(KERN_DEBUG "wcdte error: unexpected command response received (sent: %04X, received: %04X)\n", wc->last_command_sent, rcommand);
- }
- up(&wc->cmdqsem);
- }
- else
- {
- wc->last_rseqno = readchunk[16];
- wc->rcvflags = RCV_CSMENCAPS_ACK;
- if (!wc->dumping)
- wake_up_interruptible(&wc->regq);
- else
- wake_up(&wc->regq);
+ /* List went not empty. */
+ cmd = get_ready_cmd(dtc);
+ }
}
+ }
- if ((readchunk[22] == 0x75) && (readchunk[23] = 0xC1))
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: received alert (0x%02X%02X) from dsp\n", readchunk[29], readchunk[28]);
- if (debug_des) {
- down(&wc->cmdqsem);
- __dump_descriptors(wc);
- up(&wc->cmdqsem);
- }
- }
+ BUG_ON(!cmd);
+ packet = cmd->data;
+
+ payload_bytes = be16_to_cpu(packet->udphdr.len) - sizeof(struct rtphdr) -
+ sizeof(struct udphdr);
- if (wc->dumping && (readchunk[22] == 0x04) && (readchunk[23] = 0x14)) {
- printk(KERN_DEBUG);
- for (i = 27; i < 227; i++)
- printk("%02X ", readchunk[i]);
- printk("\n");
- }
+ if (count < payload_bytes) {
+ DTE_PRINTK(ERR, "Insufficient room to copy read data. Dropping packet.\n");
+ free_cmd(cmd);
+ return -EFBIG;
}
- /* IP/UDP in packet */
- else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00)
- && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78))
- {
- rchannel = (readchunk[37] | (readchunk[36] << 8)) - 0x5000;
- rlen = (readchunk[39] | (readchunk[38] << 8)) - 20;
- rtp_rseq = (readchunk[45] | (readchunk[44] << 8));
- rcodec = readchunk[43];
-
- ztc_ndx = rchannel/2;
-
- if (ztc_ndx >= wc->numchannels)
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, wc->numchannels);
- rcodec = DTE_FORMAT_UNDEF;
- }
+ atomic_inc(&cpvt->stats.packets_received);
- if ((rcodec == 0x00) || (rcodec == 0x08)) /* ulaw or alaw (decoders) */
- {
- ztc = &(wc->udecode->channels[ztc_ndx]);
- zth = ztc->tch;
- st = ztc->pvt;
-
- if (zth == NULL)
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
- if (debug_des) {
- down(&wc->cmdqsem);
- __dump_descriptors(wc);
- up(&wc->cmdqsem);
- }
- rcodec = DTE_FORMAT_UNDEF;
- } else {
- chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
- st->packets_received++;
- }
+ if (0 == cpvt->wctc4xxp_seqno_rcv) {
+ cpvt->wctc4xxp_seqno_rcv = 1;
+ cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno);
+ } else {
+ rtp_eseq = ++cpvt->last_dte_seqno;
+ if ( packet->rtphdr.seqno != rtp_eseq )
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "Bad seqno from DTE! [%04X][%d][%d][%d]\n",
+ be16_to_cpu(packet->rtphdr.seqno),
+ (be16_to_cpu(packet->udphdr.dest) - 0x5000),
+ be16_to_cpu(packet->rtphdr.seqno),
+ cpvt->last_dte_seqno);
+
+ cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno);
+ }
- }
-
- if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */
- {
- ztc = &(wc->uencode->channels[ztc_ndx]);
- zth = ztc->tch;
- st = ztc->pvt;
-
- if (zth == NULL)
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
- if (debug_des) {
- down(&wc->cmdqsem);
- __dump_descriptors(wc);
- up(&wc->cmdqsem);
- }
- rcodec = DTE_FORMAT_UNDEF;
- } else {
- chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
- st->packets_received++;
- }
+ if (unlikely(copy_to_user(frame, &packet->payload[0], payload_bytes))) {
+ DTE_PRINTK(ERR, "Failed to copy data in %s\n", __FUNCTION__);
+ free_cmd(cmd);
+ return -EFAULT;
+ }
- }
+ free_cmd(cmd);
- if (st->dte_seqno_rcv == 0)
- {
- st->dte_seqno_rcv = 1;
- st->last_dte_seqno = rtp_rseq;
- } else {
- rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF;
- if ( (rtp_rseq != rtp_eseq) && debug )
- printk(KERN_NOTICE "wcdte error: Bad seqno from DTE! [%04X][%d][%d][%d]\n", (readchunk[37] | (readchunk[36] << 8)), rchannel, rtp_rseq, st->last_dte_seqno);
+ return payload_bytes;
+}
- st->last_dte_seqno = rtp_rseq;
- }
+/* Called with a frame in the srcfmt that is to be transcoded into the dstfmt. */
+static ssize_t
+wctc4xxp_write(struct file *file, const char __user *frame, size_t count, loff_t *ppos)
+{
+ struct dahdi_transcoder_channel *dtc = file->private_data;
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct wcdte *wc = cpvt->wc;
+ struct tcb *cmd;
- if (rcodec == 0x00) /* ulaw */
- {
- if (dahdi_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == DAHDI_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == DAHDI_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
- for (i = 0; i < rlen; i++)
- chars[i] = readchunk[i+54];
+ BUG_ON(!cpvt);
+ BUG_ON(!wc);
- zth->dstlen += rlen;
- zth->dstsamples = zth->dstlen;
+ if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
+ /* The shudown flags can also be set if there is a
+ * catastrophic failure. */
+ return -EIO;
+ }
- } else {
- ztc->errorstatus = -EOVERFLOW;
- }
- dahdi_transcoder_alert(ztc);
- }
- else if (rcodec == 0x08) /* alaw */
- {
- if (dahdi_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == DAHDI_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == DAHDI_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+ if (!test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags)) {
+ return -EAGAIN;
+ }
- for (i = 0; i < rlen; i++)
- chars[i] = readchunk[i+54];
+ if (count < 2) {
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "Cannot request to transcode a packet that is less than 2 bytes.\n");
+ return -EINVAL;
+ }
- zth->dstlen += rlen;
- zth->dstsamples = zth->dstlen;
+ if (unlikely(count > SFRAME_SIZE - sizeof(struct rtp_packet))) {
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "Cannot transcode packet of %Zu bytes. This exceeds the " \
+ "maximum size of %d bytes.\n", count,
+ SFRAME_SIZE - sizeof(struct rtp_packet));
+ return -EINVAL;
+ }
- } else {
- ztc->errorstatus = -EOVERFLOW;
- }
- dahdi_transcoder_alert(ztc);
+ if (DAHDI_FORMAT_G723_1 == dtc->srcfmt) {
+ if (G723_5K_BYTES != count) {
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "Trying to transcode packet into G723 format " \
+ "that is %Zu bytes instead of the expected " \
+ "%d bytes.\n", count, G723_5K_BYTES);
+ return -EINVAL;
}
- else if (rcodec == 0x04) /* G.723.1 */
- {
- if (dahdi_tc_sanitycheck(zth, rlen) &&
- ((rlen == G723_6K_BYTES) || (rlen == G723_5K_BYTES) || (rlen == G723_SID_BYTES)))
- {
- for (i = 0; i < rlen; i++)
- chars[i] = readchunk[i+54];
+ }
- zth->dstlen += rlen;
- zth->dstsamples += G723_SAMPLES;
+ if (!(cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count))) {
+ return -ENOMEM;
+ }
+ /* Copy the data directly from user space into the command buffer. */
+ if (copy_from_user(&((struct rtp_packet*)(cmd->data))->payload[0], frame, count)) {
+ DTE_PRINTK(ERR, "Failed to copy packet from userspace.\n");
+ free_cmd(cmd);
+ return -EFAULT;
+ }
+ cpvt->seqno += 1;
+ cpvt->timestamp += count;
- } else {
- ztc->errorstatus = -EOVERFLOW;
- }
+ DTE_DEBUG(DTE_DEBUG_RTP_TX,
+ "Sending packet of %Zu byte on channel (%p).\n", count, dtc);
- if (!(zth->dstsamples % G723_SAMPLES))
- {
- dahdi_transcoder_alert(ztc);
- }
- }
- else if (rcodec == 0x12) /* G.729a */
- {
- if (dahdi_tc_sanitycheck(zth, rlen) && (rlen == G729_BYTES))
- {
- for (i = 0; i < rlen; i++)
- chars[i] = readchunk[i+54];
+ wctc4xxp_transmit_cmd(wc, cmd);
+ atomic_inc(&cpvt->stats.packets_sent);
- zth->dstlen += rlen;
- zth->dstsamples = zth->dstlen * 8;
+ return count;
+}
- } else {
- ztc->errorstatus = -EOVERFLOW;
- }
+static void
+wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
+{
+ struct tcb *cmd;
+ struct csm_encaps_hdr *hdr;
+ if (!(cmd = __alloc_cmd(ALLOC_FLAGS, 0))) {
+ WARN_ON(1);
+ return;
+ }
+ hdr = cmd->data;
+ BUG_ON(sizeof(*hdr) > cmd->data_len);
+ setup_common_header(wc, hdr);
+ hdr->op_code = cpu_to_be16(0x0001);
+ hdr->seq_num = seqno;
+ hdr->control = 0xe0;
+ hdr->channel = channel;
+
+ cmd->data_len = sizeof(*hdr);
+ wctc4xxp_transmit_cmd(wc, cmd);
+}
- if (!(zth->dstsamples % G729_SAMPLES))
- {
- dahdi_transcoder_alert(ztc);
- }
+static void
+do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
+{
+ const struct csm_encaps_hdr *listhdr;
+ const struct csm_encaps_hdr *rxhdr;
+ struct tcb *pos;
+ struct tcb *temp;
+
+ rxhdr = cmd->data;
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) {
+ listhdr = pos->data;
+ if ((listhdr->function == rxhdr->function) &&
+ (listhdr->channel == rxhdr->channel)) {
+ list_del_init(&pos->node);
+ pos->flags &= ~(__WAIT_FOR_RESPONSE);
+ WARN_ON(pos->response);
+ pos->response = cmd;
+ complete(&pos->complete);
+ break;
}
}
+ spin_unlock_bh(&wc->cmd_list_lock);
+}
+
+static void
+do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
+{
+ const struct csm_encaps_hdr *listhdr;
+ const struct csm_encaps_hdr *rxhdr;
+ struct tcb *pos;
+ struct tcb *temp;
+
+ rxhdr = cmd->data;
+
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) {
+ listhdr = pos->data;
+ if (cpu_to_be16(0xefed) == listhdr->ethhdr.h_proto) {
+ wc->seq_num = (rxhdr->seq_num + 1) & 0xff;
+ WARN_ON(!(pos->flags & DO_NOT_AUTO_FREE));
+ list_del_init(&pos->node);
+ complete(&pos->complete);
+ } else if ((listhdr->seq_num == rxhdr->seq_num) &&
+ (listhdr->channel == rxhdr->channel)) {
+ if (pos->flags & __WAIT_FOR_RESPONSE) {
+ pos->flags &= ~(__WAIT_FOR_ACK);
+ } else {
+ list_del_init(&pos->node);
+
+ if (pos->flags & DO_NOT_AUTO_FREE) {
+ complete(&pos->complete);
+ } else {
+ free_cmd(pos);
+ }
+ }
+ break;
+ }
+ }
+ spin_unlock_bh(&wc->cmd_list_lock);
+
+ /* There is never a reason to store up the ack packets. */
+ free_cmd(cmd);
}
+static inline int
+is_response(const struct csm_encaps_hdr *hdr)
+{
+ return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0;
+}
+static void
+receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
+{
+ const struct csm_encaps_hdr *hdr = cmd->data;
+ if (!(hdr->control & MESSAGE_PACKET)) {
+ if (!(hdr->control & SUPPRESS_ACK)) {
+ wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel);
+ }
-/* static inline int wcdte_check_descriptor(struct wcdte *wc) */
-static int wcdte_check_descriptor(struct wcdte *wc)
+ if (is_response(hdr)) {
+ do_rx_response_packet(wc, cmd);
+ } else if (0xc1 == hdr->type) {
+ if (0x75 == hdr->class) {
+ DTE_PRINTK(WARNING,
+ "Received alert (0x%04x) from dsp\n",
+ le16_to_cpu(hdr->params[0]));
+ }
+ free_cmd(cmd);
+ } else if (0xd4 == hdr->type) {
+ if (hdr->params[0] != le16_to_cpu(0xffff)) {
+ DTE_PRINTK(WARNING,
+ "DTE Failed self test (%04x).\n",
+ le16_to_cpu(hdr->params[0]));
+ } else if (hdr->params[1] != le16_to_cpu(0x000c)) {
+ DTE_PRINTK(WARNING,
+ "Unexpected ERAM status (%04x).\n",
+ le16_to_cpu(hdr->params[1]));
+ } else {
+ wctc4xxp_set_ready(wc);
+ wake_up(&wc->waitq);
+ }
+ free_cmd(cmd);
+ } else {
+ DTE_PRINTK(WARNING, "Unknown command type received. %02x\n", hdr->type);
+ free_cmd(cmd);
+ }
+ } else {
+ do_rx_ack_packet(wc, cmd);
+ }
+}
+
+static void
+queue_rtp_packet(struct wcdte *wc, struct tcb *cmd)
{
- int o2 = 0;
+ int index;
+ struct dahdi_transcoder_channel *dtc;
+ struct channel_pvt *cpvt;
+ struct rtp_packet *packet = cmd->data;
+
+ index = (be16_to_cpu(packet->udphdr.dest) - 0x5000) / 2;
+ if (unlikely(index >= wc->numchannels)) {
+ DTE_PRINTK(ERR, "Invalid channel number in response from DTE.\n");
+ free_cmd(cmd);
+ return;
+ }
- o2 += ERING_SIZE * 4;
- o2 += wc->rdbl * 4;
+ switch (packet->rtphdr.type) {
+ case 0x00:
+ case 0x08:
+ dtc = &(wc->udecode->channels[index]);
+ break;
+ case 0x04:
+ case 0x12:
+ dtc = &(wc->uencode->channels[index]);
+ break;
+ default:
+ DTE_PRINTK(ERR, "Unknown codec in packet (0x%02x).\n",\
+ packet->rtphdr.type);
+ free_cmd(cmd);
+ return;
+ }
+
+ cpvt = dtc->pvt;
+ spin_lock_bh(&cpvt->lock);
+ list_add_tail(&cmd->node, &cpvt->rx_queue);
+ spin_unlock_bh(&cpvt->lock);
+ dahdi_tc_set_data_waiting(dtc);
+ dahdi_transcoder_alert(dtc);
+ return;
+}
- if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) {
- wc->rxints++;
- wcdte_receiveprep(wc, wc->rdbl);
- wcdte_reinit_descriptor(wc, 0, wc->rdbl, "rxchk");
- wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
+static inline void
+wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd)
+{
+ const struct ethhdr *ethhdr = (const struct ethhdr*)(cmd->data);
- return 1;
+ if (cpu_to_be16(ETH_P_IP) == ethhdr->h_proto) {
+ queue_rtp_packet(wc, cmd);
+ } else if (cpu_to_be16(ETH_P_CSM_ENCAPS) == ethhdr->h_proto) {
+ receive_csm_encaps_packet(wc, cmd);
+ } else {
+ DTE_PRINTK(WARNING,
+ "Unknown packet protocol recieved: %04x.\n",
+ be16_to_cpu(ethhdr->h_proto));
+ free_cmd(cmd);
}
- return 0;
}
-static void wcdte_init_descriptors(struct wcdte *wc)
+static inline void service_dte(struct wcdte *wc)
{
- volatile unsigned int *descrip;
- dma_addr_t descripdma;
- dma_addr_t writedma;
- dma_addr_t readdma;
- int x;
-
- descrip = wc->descripchunk;
- descripdma = wc->descripdma;
- writedma = wc->writedma;
- readdma = wc->readdma;
-
- for (x=0;x<ERING_SIZE;x++) {
- if (x < ERING_SIZE - 1)
- descripdma += 16;
- else
- descripdma = wc->descripdma;
-
- /* Transmit descriptor */
- descrip[0 ] = cpu_to_le32(0x00000000);
- descrip[1 ] = cpu_to_le32(0xe5800000 | (SFRAME_SIZE));
- descrip[2 ] = cpu_to_le32(writedma + x*SFRAME_SIZE);
- descrip[3 ] = cpu_to_le32(descripdma);
-
- /* Receive descriptor */
- descrip[0 + ERING_SIZE * 4] = cpu_to_le32(0x80000000);
- descrip[1 + ERING_SIZE * 4] = cpu_to_le32(0x01000000 | (SFRAME_SIZE));
- descrip[2 + ERING_SIZE * 4] = cpu_to_le32(readdma + x*SFRAME_SIZE);
- descrip[3 + ERING_SIZE * 4] = cpu_to_le32(descripdma + ERING_SIZE * 16);
+ struct tcb *cmd;
+
+ /*
+ * Process the received packets
+ */
+ while((cmd = wctc4xxp_retrieve(wc->rxd))) {
+ struct tcb *newcmd;
+
+ wctc4xxp_net_capture_cmd(wc, cmd);
+
+ if(!(newcmd = __alloc_cmd(ALLOC_FLAGS, 0))) {
+ DTE_PRINTK(ERR, "Out of memory in %s.\n", __FUNCTION__);
+ } else {
+ newcmd->data = kmalloc(1518, ALLOC_FLAGS);
+ if (!newcmd->data) {
+ DTE_PRINTK(ERR, "out of memory in %s " \
+ "again.\n", __FUNCTION__);
+ }
+ newcmd->data_len = 1518;
+ if (wctc4xxp_submit(wc->rxd, newcmd)) {
+ DTE_PRINTK(ERR, "Failed submit in %s\n", __FUNCTION__);
+ free_cmd(newcmd);
+ }
+ wctc4xxp_receive_demand_poll(wc);
+ }
+ wctc4xxp_receiveprep(wc, cmd);
+ }
+ wctc4xxp_receive_demand_poll(wc);
- /* Advance descriptor */
- descrip += 4;
- }
+ /*
+ * Process the transmit packets
+ */
+ while((cmd = wctc4xxp_retrieve(wc->txd))) {
+ if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) {
+ spin_lock_bh(&wc->cmd_list_lock);
+ list_del_init(&cmd->node);
+ spin_unlock_bh(&wc->cmd_list_lock);
+ if (DO_NOT_AUTO_FREE & cmd->flags) {
+ complete(&cmd->complete);
+ } else {
+ free_cmd(cmd);
+ }
+ }
+ /* We've freed up a spot in the hardware ring buffer. If
+ * another packet is queued up, let's submit it to the
+ * hardware. */
+ spin_lock_bh(&wc->cmd_list_lock);
+ if (!list_empty(&wc->cmd_list)) {
+ cmd = list_entry(wc->cmd_list.next, struct tcb, node);
+ list_del_init(&cmd->node);
+ } else {
+ cmd = NULL;
+ }
+ spin_unlock_bh(&wc->cmd_list_lock);
+
+ if (cmd) {
+ wctc4xxp_transmit_cmd(wc, cmd);
+ }
+ }
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-static void dte_wque_run(struct work_struct *work)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void deferred_work_func(void *param)
{
- struct wcdte *wc = container_of(work, struct wcdte, dte_work);
+ struct wcdte *wc = param;
#else
-static void dte_wque_run(void *work_data)
+static void deferred_work_func(struct work_struct *work)
{
- struct wcdte *wc = work_data;
+ struct wcdte *wc = container_of(work, struct wcdte, deferred_work);
#endif
- int res;
-
- do {
- res = wcdte_check_descriptor(wc);
- } while(res);
-
- transmit_demand(wc);
+ service_dte(wc);
}
-DAHDI_IRQ_HANDLER(wcdte_interrupt)
+DAHDI_IRQ_HANDLER(wctc4xxp_interrupt)
{
struct wcdte *wc = dev_id;
- unsigned int ints;
+ u32 ints;
+ u32 reg;
+#define TX_COMPLETE_INTERRUPT 0x00000001
+#define RX_COMPLETE_INTERRUPT 0x00000040
+#define NORMAL_INTERRUPTS (TX_COMPLETE_INTERRUPT | RX_COMPLETE_INTERRUPT)
/* Read and clear interrupts */
- ints = wcdte_getctl(wc, 0x0028);
- wcdte_setctl(wc, 0x0028, ints);
+ ints = __wctc4xxp_getctl(wc, 0x0028);
+ ints &= wc->intmask;
+
if (!ints)
return IRQ_NONE;
- ints &= wc->intmask;
- if (ints & 0x00000041) {
- wc->wqueints = ints;
- queue_work(wc->dte_wq, &wc->dte_work);
- }
-
- if ((ints & 0x00008000) && debug)
- printk(KERN_DEBUG "wcdte: Abnormal Interrupt: \n");
+ if (likely(ints & NORMAL_INTERRUPTS)) {
+ reg = 0;
+ if (ints & TX_COMPLETE_INTERRUPT) {
+ reg |= TX_COMPLETE_INTERRUPT;
+ }
+ if (ints & RX_COMPLETE_INTERRUPT) {
+ reg |= RX_COMPLETE_INTERRUPT;
+ }
+#if DEFERRED_PROCESSING == WORKQUEUE
+ schedule_work(&wc->deferred_work);
+#elif DEFERRED_PROCESSING == INTERRUPT
+#error "You will need to change the locks if you want to run the processing in the interrupt handler."
+#else
+#error "Define a deferred processing function in kernel/wctc4xxp/wctc4xxp.h"
+#endif
+ __wctc4xxp_setctl(wc, 0x0028, reg);
+ } else {
+ if ((ints & 0x00008000) && debug)
+ DTE_PRINTK(INFO, "Abnormal Interrupt.\n");
- if ((ints & 0x00002000) && debug)
- printk(KERN_DEBUG "wcdte: Fatal Bus Error INT\n");
+ if ((ints & 0x00002000) && debug)
+ DTE_PRINTK(INFO, "Fatal Bus Error INT\n");
- if ((ints & 0x00000100) && debug)
- printk(KERN_DEBUG "wcdte: Receive Stopped INT\n");
+ if ((ints & 0x00000100) && debug)
+ DTE_PRINTK(INFO, "Receive Stopped INT\n");
- if ((ints & 0x00000080) && debug)
- printk(KERN_DEBUG "wcdte: Receive Desciptor Unavailable INT\n");
+ if ((ints & 0x00000080) && debug) {
+ DTE_PRINTK(INFO, "Receive Desciptor Unavailable INT " \
+ "(%d)\n", wctc4xxp_getcount(wc->rxd));
+ }
- if ((ints & 0x00000020) && debug)
- printk(KERN_DEBUG "wcdte: Transmit Under-flow INT\n");
+ if ((ints & 0x00000020) && debug)
+ DTE_PRINTK(INFO, "Transmit Under-flow INT\n");
- if ((ints & 0x00000008) && debug)
- printk(KERN_DEBUG "wcdte: Jabber Timer Time-out INT\n");
+ if ((ints & 0x00000008) && debug)
+ DTE_PRINTK(INFO, "Jabber Timer Time-out INT\n");
- if ((ints & 0x00000004) && debug)
- printk(KERN_DEBUG "wcdte: Transmit Descriptor Unavailable INT\n");
+ if ((ints & 0x00000004) && debug)
+ ; // printk("wcdte: Transmit Descriptor Unavailable INT\n");
- if ((ints & 0x00000002) && debug)
- printk(KERN_DEBUG "wcdte: Transmit Processor Stopped INT\n");
+ if ((ints & 0x00000002) && debug)
+ DTE_PRINTK(INFO, "Transmit Processor Stopped INT\n");
- return IRQ_RETVAL(1);
-
+ /* Clear all the pending interrupts. */
+ __wctc4xxp_setctl(wc, 0x0028, ints);
+ }
+ return IRQ_HANDLED;
}
-static int wcdte_hardware_init(struct wcdte *wc)
+static int
+wctc4xxp_hardware_init(struct wcdte *wc)
{
/* Hardware stuff */
- unsigned int reg;
+ u32 reg;
unsigned long newjiffies;
-
- /* Initialize descriptors */
- wcdte_init_descriptors(wc);
+ u8 cache_line_size;
+ const u32 DEFAULT_PCI_ACCESS = 0xfff80000;
/* Enable I/O Access */
- pci_read_config_dword(wc->dev, 0x0004, &reg);
+ pci_read_config_dword(wc->pdev, 0x0004, &reg);
reg |= 0x00000007;
- pci_write_config_dword(wc->dev, 0x0004, reg);
-
- wcdte_setctl(wc, 0x0000, 0xFFF88001);
+ pci_write_config_dword(wc->pdev, 0x0004, reg);
- newjiffies = jiffies + HZ/10;
- while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies));
+ if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size)) {
+ /* \todo Print an error message... */
+ return -EIO;
+ }
+ switch (cache_line_size) {
+ case 0x08:
+ reg = DEFAULT_PCI_ACCESS | (0x1 << 14);
+ break;
+ case 0x10:
+ reg = DEFAULT_PCI_ACCESS | (0x2 << 14);
+ break;
+ case 0x20:
+ reg = DEFAULT_PCI_ACCESS | (0x3 << 14);
+ break;
+ default:
+ reg = 0xfe584202;
+ break;
+ }
+
+ reg |= ((wc->txd->padding / sizeof(u32)) << 2) & 0x7c;
+
+ /* Reset the DTE... */
+ wctc4xxp_setctl(wc, 0x0000, reg | 1);
+ newjiffies = jiffies + HZ; /* One second timeout */
+ /* ...and wait for it to come out of reset. */
+ while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) {
+ msleep(1);
+ }
- wcdte_setctl(wc, 0x0000, 0xFFFA0000);
+ wctc4xxp_setctl(wc, 0x0000, reg);
/* Configure watchdogs, access, etc */
- wcdte_setctl(wc, 0x0030, 0x00280048);
- wcdte_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
+ wctc4xxp_setctl(wc, 0x0030, 0x00280048);
+ wctc4xxp_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
- reg = wcdte_getctl(wc, 0x00fc);
- wcdte_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
+ reg = wctc4xxp_getctl(wc, 0x00fc);
+ wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
- reg = wcdte_getctl(wc, 0x00fc);
+ reg = wctc4xxp_getctl(wc, 0x00fc);
return 0;
}
-static void wcdte_setintmask(struct wcdte *wc, unsigned int intmask)
+static void
+wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask)
{
wc->intmask = intmask;
- wcdte_setctl(wc, 0x0038, intmask);
+ wctc4xxp_setctl(wc, 0x0038, intmask);
}
-static void wcdte_enable_interrupts(struct wcdte *wc)
+static void
+wctc4xxp_enable_interrupts(struct wcdte *wc)
{
- /* Enable interrupts */
- if (!debug)
- wcdte_setintmask(wc, 0x00010041);
- else
- wcdte_setintmask(wc, 0x0001A1EB);
+ wctc4xxp_setintmask(wc, 0x000180c1);
+ // wctc4xxp_setintmask(wc, 0xffffffff);
}
-static void wcdte_start_dma(struct wcdte *wc)
+static void
+wctc4xxp_start_dma(struct wcdte *wc)
{
- unsigned int reg;
+ int res;
+ int i;
+ u32 reg;
+ struct tcb *cmd;
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ if (!(cmd = alloc_cmd())) {
+ WARN();
+ return;
+ }
+ cmd->data_len = SFRAME_SIZE;
+ if ((res=wctc4xxp_submit(wc->rxd, cmd))) {
+ /* When we're starting the DMA, we should always be
+ * able to fill the ring....so something is wrong
+ * here. */
+ WARN();
+ free_cmd(cmd);
+ break;
+ }
+ }
wmb();
- wcdte_setctl(wc, 0x0020, wc->descripdma);
- wcdte_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
+ wctc4xxp_setctl(wc, 0x0020, wc->txd->desc_dma);
+ wctc4xxp_setctl(wc, 0x0018, wc->rxd->desc_dma);
+
/* Start receiver/transmitter */
- reg = wcdte_getctl(wc, 0x0030);
- wcdte_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */
- wcdte_setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */
- reg = wcdte_getctl(wc, 0x0028);
- wcdte_setctl(wc, 0x0028, reg);
+ reg = wctc4xxp_getctl(wc, 0x0030);
+ wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */
+ wctc4xxp_receive_demand_poll(wc);
+ reg = wctc4xxp_getctl(wc, 0x0028);
+ wctc4xxp_setctl(wc, 0x0028, reg);
}
-static void wcdte_stop_dma(struct wcdte *wc)
+static void
+wctc4xxp_stop_dma(struct wcdte *wc)
{
/* Disable interrupts and reset */
unsigned int reg;
+ unsigned long newjiffies;
/* Disable interrupts */
- wcdte_setintmask(wc, 0x00000000);
- wcdte_setctl(wc, 0x0084, 0x00000000);
- wcdte_setctl(wc, 0x0048, 0x00000000);
+ wctc4xxp_setintmask(wc, 0x00000000);
+ wctc4xxp_setctl(wc, 0x0084, 0x00000000);
+ wctc4xxp_setctl(wc, 0x0048, 0x00000000);
/* Reset the part to be on the safe side */
- reg = wcdte_getctl(wc, 0x0000);
+ reg = wctc4xxp_getctl(wc, 0x0000);
reg |= 0x00000001;
- wcdte_setctl(wc, 0x0000, reg);
-}
+ wctc4xxp_setctl(wc, 0x0000, reg);
-static void wcdte_disable_interrupts(struct wcdte *wc)
-{
- /* Disable interrupts */
- wcdte_setintmask(wc, 0x00000000);
- wcdte_setctl(wc, 0x0084, 0x00000000);
+ newjiffies = jiffies + HZ; /* One second timeout */
+ /* We'll wait here for the part to come out of reset */
+ while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) {
+ msleep(1);
+ }
}
-static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int wait_mode)
+static void
+wctc4xxp_disable_interrupts(struct wcdte *wc)
{
- int ret;
-
-
- if (wait_mode == 1)
- ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
- else if (wait_mode == 2)
- ret = wait_event_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
- else {
- if (!debug_notimeout) {
- ret = wait_event_timeout(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout);
- }
- else {
- ret = wait_event_interruptible(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)));
- if (ret == 0)
- ret = 1;
- }
- }
- wc->rcvflags = 0;
- wc->last_rcommand = 0;
- wc->last_seqno = 0;
-
- if (ret < 0)
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret);
- return(1);
- }
- if (ret == 0)
- {
- if (debug)
- printk(KERN_DEBUG "wcdte error: Waitfor CSMENCAPS response timed out (ret = %d) (cmd_snt = %04X)\n", ret, wc->last_command_sent);
- if (debug_des) {
- down(&wc->cmdqsem);
- __dump_descriptors(wc);
- up(&wc->cmdqsem);
- }
- return(2);
- }
- if (wait_mode == 0)
- wc->last_command_sent = 999;
- wc->last_rseqno = 999;
- return(0);
+ /* Disable interrupts */
+ wctc4xxp_setintmask(wc, 0x00000000);
+ wctc4xxp_setctl(wc, 0x0084, 0x00000000);
}
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
-static int wcdte_read_phy(struct wcdte *wc, int location)
+static int
+wctc4xxp_read_phy(struct wcdte *wc, int location)
{
int i;
long mdio_addr = 0x0048;
@@ -1365,34 +2255,36 @@ static int wcdte_read_phy(struct wcdte *wc, int location)
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
- wcdte_getctl(wc, mdio_addr);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wctc4xxp_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
+
/* Shift the read command bits out. */
for (i = 17; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
- wcdte_getctl(wc, mdio_addr);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wctc4xxp_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
- wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
- wcdte_getctl(wc, mdio_addr);
- retval = (retval << 1) | ((wcdte_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wctc4xxp_getctl(wc, mdio_addr);
+ retval = (retval << 1) | ((wctc4xxp_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
retval = (retval>>1) & 0xffff;
return retval;
}
-void wcdte_write_phy(struct wcdte *wc, int location, int value)
+static void
+wctc4xxp_write_phy(struct wcdte *wc, int location, int value)
{
int i;
int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value;
@@ -1400,264 +2292,620 @@ void wcdte_write_phy(struct wcdte *wc, int location, int value)
/* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
- wcdte_getctl(wc, mdio_addr);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wctc4xxp_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
/* Shift the command bits out. */
for (i = 31; i >= 0; i--) {
int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
- wcdte_getctl(wc, mdio_addr);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wctc4xxp_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
- wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
- wcdte_getctl(wc, mdio_addr);
- wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
- wcdte_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wctc4xxp_getctl(wc, mdio_addr);
+ wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wctc4xxp_getctl(wc, mdio_addr);
}
return;
}
-static int wcdte_boot_processor(struct wcdte *wc, const struct firmware *firmware, int full)
+static int
+wctc4xxp_wait_for_link(struct wcdte *wc)
+{
+ int reg;
+ unsigned int delay_count = 0;
+ do {
+ reg = wctc4xxp_getctl(wc, 0x00fc);
+ mdelay(2);
+ delay_count++;
+
+ if (delay_count >= 5000) {
+ DTE_PRINTK(ERR, "Failed to link to DTE processor!\n");
+ return -EIO;
+ }
+ } while ((reg & 0xE0000000) != 0xE0000000);
+ return 0;
+}
+
+static int
+wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware)
{
- int i, j, byteloc, last_byteloc, length, delay_count;
- unsigned int reg, ret;
+ unsigned int byteloc;
+ unsigned int last_byteloc;
+ unsigned int length;
+ struct tcb *cmd;
+
+ byteloc = 17;
+
+ if (!(cmd = alloc_cmd())) {
+ return -ENOMEM;
+ }
+ if (1518 > cmd->data_len) {
+ cmd->data = kmalloc(1518, GFP_KERNEL);
+ if (!(cmd->data)) {
+ free_cmd(cmd);
+ return -ENOMEM;
+ }
+ cmd->data_len = 1518;
+ }
+ while (byteloc < (firmware->size-20)) {
+ last_byteloc = byteloc;
+ length = (firmware->data[byteloc] << 8) | firmware->data[byteloc+1];
+ byteloc += 2;
+ cmd->data_len = length;
+ BUG_ON(length > cmd->data_len);
+ memcpy(cmd->data, &firmware->data[byteloc], length);
+ byteloc += length;
+ cmd->flags = WAIT_FOR_ACK;
+ wctc4xxp_transmit_cmd(wc, cmd);
+ wait_for_completion(&cmd->complete);
+ if (cmd->flags & DTE_CMD_TIMEOUT) {
+ free_cmd(cmd);
+ DTE_PRINTK(ERR, "Failed to load firmware.\n");
+ return -EIO;
+ }
+ }
+ free_cmd(cmd);
+ if (!wait_event_timeout(wc->waitq, wctc4xxp_is_ready(wc), 15*HZ)) {
+ DTE_PRINTK(ERR, "Failed to boot firmware.\n");
+ return -EIO;
+ }
+ return 0;
+}
-#ifndef USE_TEST_HW
+static int
+wctc4xxp_turn_off_booted_led(struct wcdte *wc)
+{
+ int ret = 0;
+ int reg;
/* Turn off auto negotiation */
- wcdte_write_phy(wc, 0, 0x2100);
- if (debug)
- printk(KERN_DEBUG "wcdte: PHY register 0 = %X", wcdte_read_phy(wc, 0));
+ wctc4xxp_write_phy(wc, 0, 0x2100);
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n",
+ wctc4xxp_read_phy(wc, 0));
/* Set reset */
- wcdte_setctl(wc, 0x00A0, 0x04000000);
+ wctc4xxp_setctl(wc, 0x00A0, 0x04000000);
- /* Wait 1000msec to ensure processor reset */
+ /* Wait 4 ms to ensure processor reset */
mdelay(4);
/* Clear reset */
- wcdte_setctl(wc, 0x00A0, 0x04080000);
-
- /* Waitfor ethernet link */
- delay_count = 0;
- do
- {
- reg = wcdte_getctl(wc, 0x00fc);
- mdelay(2);
- delay_count++;
-
- if (delay_count >= 5000)
- {
- printk(KERN_NOTICE "wcdte error: Failed to link to DTE processor!\n");
- return(1);
- }
- } while ((reg & 0xE0000000) != 0xE0000000);
+ wctc4xxp_setctl(wc, 0x00A0, 0x04080000);
+ /* Wait for the ethernet link */
+ if ((ret = wctc4xxp_wait_for_link(wc))) {
+ return ret;
+ }
/* Turn off booted LED */
- wcdte_setctl(wc, 0x00A0, 0x04084000);
-
-
-#endif
+ wctc4xxp_setctl(wc, 0x00A0, 0x04084000);
+ reg = wctc4xxp_getctl(wc, 0x00fc);
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "LINK STATUS: reg(0xfc) = %X\n", reg);
- reg = wcdte_getctl(wc, 0x00fc);
- if (debug)
- printk(KERN_DEBUG "wcdte: LINK STATUS: reg(0xfc) = %X\n", reg);
+ reg = wctc4xxp_getctl(wc, 0x00A0);
- reg = wcdte_getctl(wc, 0x00A0);
+ return ret;
+}
- byteloc = 17;
- j = 0;
- do
- {
- last_byteloc = byteloc;
+static void
+wctc4xxp_turn_on_booted_led(struct wcdte *wc)
+{
+ wctc4xxp_setctl(wc, 0x00A0, 0x04080000);
+}
- length = (firmware->data[byteloc] << 8) |firmware->data[byteloc+1];
- byteloc += 2;
-
- down(&wc->cmdqsem);
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
- printk(KERN_NOTICE "wcdte error: cmdq is full.\n");
- else
- {
- wc->cmdq[wc->cmdq_wndx].cmdlen = length;
- for (i = 0; i < length; i++)
- wc->cmdq[wc->cmdq_wndx].cmd[i] = firmware->data[byteloc++];
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
- }
-
- ret = __transmit_demand(wc);
- up(&wc->cmdqsem);
-
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 1);
- if (ret == 1)
- return(1);
- else if (ret == 2) /* Retransmit if dte processor times out */
- byteloc = last_byteloc;
- j++;
-
- if (!full && (byteloc > 189)) { /* Quit if not fully booting */
- wcdte_setctl(wc, 0x00A0, 0x04080000);
- return 0;
- }
+static int
+wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware)
+{
+ int ret;
+ wctc4xxp_turn_off_booted_led(wc);
- } while (byteloc < firmware->size-20);
- wc->timeout = 10 * HZ;
- wc->last_command_sent = 0;
- if (wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 1))
- return(1);
+ if ((ret = wctc4xxp_load_firmware(wc, firmware))) {
+ return ret;
+ }
- /* Turn on booted LED */
- wcdte_setctl(wc, 0x00A0, 0x04080000);
- if(debug)
- printk(KERN_DEBUG "wcdte: Successfully booted DTE processor.\n");
+ wctc4xxp_turn_on_booted_led(wc);
- return(0);
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n");
+ return 0;
}
-static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2)
+static int
+wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
+ u8 simple, u8 complicated)
{
- int length = 0;
- unsigned char chan1, chan2;
- struct dahdi_transcoder_channel *ztc1, *ztc2;
- struct dte_state *st1, *st2;
- if(complicated == DTE_FORMAT_G729A)
- length = G729_LENGTH;
- else if (complicated == DTE_FORMAT_G723_1)
- length = G723_LENGTH;
+ int res;
+ int length;
+ u8 chan1, chan2;
+ struct dahdi_transcoder_channel *dtc1, *dtc2;
+ struct channel_pvt *cpvt1, *cpvt2;
+ /* \todo what do these part variable names mean? */
+ unsigned int timeslot;
+ unsigned int part2_id;
+ struct tcb *cmd;
+ const struct csm_encaps_hdr *hdr;
+
+
+ BUG_ON(!wc || !cpvt);
+ if (cpvt->encoder) {
+ timeslot = cpvt->timeslot_in_num;
+ part2_id = cpvt->timeslot_out_num;
+ } else {
+ u8 temp;
+ timeslot = cpvt->timeslot_out_num;
+ part2_id = cpvt->timeslot_in_num;
+ temp = simple;
+ simple = complicated;
+ complicated = temp;
+ }
- /* Create complex channel */
- dahdi_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
- dahdi_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
- chan1 = wc->last_rparm1;
+ length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
+ (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;
- /* Create simple channel */
- dahdi_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
- dahdi_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
- chan2 = wc->last_rparm1;
+ if (!(cmd = wctc4xxp_create_channel_cmd(wc, timeslot))) {
+ return -ENOMEM;
+ }
+ if ((res=wctc4xxp_transmit_cmd_and_wait(wc, cmd))) {
+ free_cmd(cmd);
+ return res;
+ }
+ free_cmd(cmd);
- ztc1 = &(wc->uencode->channels[part1_id/2]);
- ztc2 = &(wc->udecode->channels[part2_id/2]);
- st1 = ztc1->pvt;
- st2 = ztc2->pvt;
+ cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, timeslot));
+ if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) {
+ free_cmd(cmd);
+ return res;
+ }
+ WARN_ON(!cmd->response);
+ hdr = (const struct csm_encaps_hdr*)cmd->response->data;
+ chan1 = le16_to_cpu(hdr->params[0]);;
+ free_cmd(cmd);
- /* Configure complex channel */
- dahdi_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st1->cmd_seqno++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+ if (!(cmd = wctc4xxp_create_channel_cmd(wc, part2_id))) {
+ return -ENOMEM;
+ }
+ if ((res = __wctc4xxp_send_cmd(wc, cmd))) {
+ return res;
+ }
+ cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id));
+ cmd->flags |= WAIT_FOR_RESPONSE;
+ if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) {
+ return res;
+ }
+ WARN_ON(!cmd->response);
+ hdr = (const struct csm_encaps_hdr*)cmd->response->data;
+ chan2 = le16_to_cpu(hdr->params[0]);;
+ free_cmd(cmd);
+
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "DTE is using the following channels chan1: %d chan2: %d\n", chan1, chan2);
+
+ BUG_ON(timeslot/2 >= wc->numchannels);
+ BUG_ON(part2_id/2 >= wc->numchannels);
+ dtc1 = &(wc->uencode->channels[timeslot/2]);
+ dtc2 = &(wc->udecode->channels[part2_id/2]);
+ cpvt1 = dtc1->pvt;
+ cpvt2 = dtc2->pvt;
+ BUG_ON(!cpvt1);
+ BUG_ON(!cpvt2);
+ /* Configure complex channel */
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt1->cmd_seqno++, chan1, part2_id, timeslot)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt1->cmd_seqno++, chan1, length, 0)))) {
+ return res;
+ }
/* Configure simple channel */
- dahdi_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st2->cmd_seqno++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
-
-#ifdef QUIET_DSP
- dahdi_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
-#endif
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt2->cmd_seqno++, chan2, timeslot, part2_id)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt2->cmd_seqno++, chan2, length, 0)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt1->cmd_seqno++, chan1)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt1->cmd_seqno++, chan1)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt2->cmd_seqno++, chan2)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt2->cmd_seqno++, chan2)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt1->cmd_seqno++, chan1)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt2->cmd_seqno++, chan2)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt1->cmd_seqno++, chan1, complicated)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt2->cmd_seqno++, chan2, simple)))) {
+ return res;
+ }
- dahdi_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st2->cmd_seqno++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "DTE has completed setup and connected the two channels together.\n");
- *dte_chan1 = chan1;
- *dte_chan2 = chan2;
- return 1;
+ /* Save off the channels returned from the DTE so we can use then when
+ * sending the RTP packets. */
+ if (ENCODER == cpvt->encoder) {
+ cpvt->chan_in_num = chan1;
+ cpvt->chan_out_num = chan2;
+ } else {
+ cpvt->chan_out_num = chan1;
+ cpvt->chan_in_num = chan2;
+ }
+
+ return 0;
}
-static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2)
+static int
+wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt)
{
- struct dahdi_transcoder_channel *ztc1, *ztc2;
- struct dte_state *st1, *st2;
+ struct dahdi_transcoder_channel *dtc1, *dtc2;
+ struct channel_pvt *cpvt1, *cpvt2;
+ int chan1, chan2;
+ int res;
+
+ if (cpvt->encoder) {
+ chan1 = cpvt->chan_in_num;
+ chan2 = cpvt->chan_out_num;
+ } else {
+ chan1 = cpvt->chan_out_num;
+ chan2 = cpvt->chan_in_num;
+ }
+
+ if (chan1/2 >= wc->numchannels || chan2/2 >= wc->numchannels) {
+ DTE_PRINTK(WARNING,
+ "Invalid channel numbers in %s. chan1:%d chan2: %d\n",
+ __FUNCTION__, chan1/2, chan2/2);
+ return 0;
+ }
- ztc1 = &(wc->uencode->channels[chan1/2]);
- ztc2 = &(wc->udecode->channels[chan2/2]);
- st1 = ztc1->pvt;
- st2 = ztc2->pvt;
+ dtc1 = &(wc->uencode->channels[chan1/2]);
+ dtc2 = &(wc->udecode->channels[chan2/2]);
+ cpvt1 = dtc1->pvt;
+ cpvt2 = dtc2->pvt;
/* Turn off both channels */
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
- dahdi_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt1->cmd_seqno++, chan1)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt2->cmd_seqno++, chan2)))) {
+ return res;
+ }
/* Disconnect the channels */
- dahdi_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0)))) {
+ return res;
+ }
/* Remove the channels */
- dahdi_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
- dahdi_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2)))) {
+ return res;
+ }
- return 1;
+ return 0;
}
-static int __wcdte_setup_channels(struct wcdte *wc)
+static int
+__wctc4xxp_setup_channels(struct wcdte *wc)
{
- wc->seq_num = 6;
+ int res;
+ struct tcb *cmd;
-#ifndef USE_TEST_HW
- dahdi_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411);
- dahdi_send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412);
-#endif
+ if (!(cmd = alloc_cmd())) {
+ return -ENOMEM;
+ }
-#ifdef USE_TDM_CONFIG
- dahdi_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417);
- dahdi_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405);
- dahdi_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- dahdi_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- dahdi_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- dahdi_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
-#endif
+ __wctc4xxp_create_set_arm_clk_cmd(wc, cmd);
+ res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
+ free_cmd(cmd);
+ if (res) {
+ return res;
+ }
- dahdi_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100);
- dahdi_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302);
- dahdi_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105);
- dahdi_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304);
+ cmd = wctc4xxp_create_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++));
+ res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
+ free_cmd(cmd);
+ if (res) {
+ return res;
+ }
-#ifdef USE_TDM_CONFIG
- dahdi_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B);
-#endif
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++)))) {
+ return res;
+ }
- dahdi_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
- dahdi_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306);
- dahdi_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04)))) {
+ return res;
+ }
+ if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++)))) {
+ return res;
+ }
+ return 0;
+}
-#ifdef USE_TDM_CONFIG
- dahdi_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435);
-#endif
+static int
+wctc4xxp_setup_channels(struct wcdte *wc)
+{
+ int ret;
+ if ((ret=down_interruptible(&wc->chansem))) {
+ WARN();
+ return ret;
+ }
+ ret = __wctc4xxp_setup_channels(wc);
+ up(&wc->chansem);
- wc->timeout = HZ/10 + 1; /* 100msec */
+ return ret;
+}
- return(0);
+static void wctc4xxp_setup_file_operations(struct file_operations *fops)
+{
+ fops->owner = THIS_MODULE;
+ fops->read = wctc4xxp_read;
+ fops->write = wctc4xxp_write;
}
-static int wcdte_setup_channels(struct wcdte *wc)
+static int
+initialize_channel_pvt(struct wcdte *wc, encode_t type,
+ struct channel_pvt **cpvt)
{
- down(&wc->chansem);
- __wcdte_setup_channels(wc);
- up(&wc->chansem);
+ int chan;
+ *cpvt = kmalloc(sizeof(struct channel_pvt) * wc->numchannels, GFP_KERNEL);
+ if (!(*cpvt)) {
+ return -ENOMEM;
+ }
+ for (chan = 0; chan < wc->numchannels; ++chan) {
+ wctc4xxp_init_state((*cpvt) + chan, type, chan, wc);
+ }
+ return 0;
+}
+static int
+initialize_transcoder(struct wcdte *wc, unsigned int srcfmts,
+ unsigned int dstfmts, struct channel_pvt *pvts,
+ struct dahdi_transcoder **zt)
+{
+ int chan;
+ *zt = dahdi_transcoder_alloc(wc->numchannels);
+ if (!(*zt)) {
+ return -ENOMEM;
+ }
+ (*zt)->srcfmts = srcfmts;
+ (*zt)->dstfmts = dstfmts;
+ (*zt)->allocate = wctc4xxp_operation_allocate;
+ (*zt)->release = wctc4xxp_operation_release;
+ wctc4xxp_setup_file_operations(&((*zt)->fops));
+ for (chan = 0; chan < wc->numchannels; ++chan) {
+ (*zt)->channels[chan].pvt = &pvts[chan];
+ }
return 0;
}
-static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int initialize_encoders(struct wcdte *wc, unsigned int complexfmts)
{
- int res, reg;
- struct wcdte *wc;
- struct wcdte_desc *d = (struct wcdte_desc *)ent->driver_data;
- int x;
- static int initd_ifaces=0;
- unsigned char g729_numchannels, g723_numchannels, min_numchannels, dte_firmware_ver, dte_firmware_ver_minor;
- unsigned int complexfmts;
+ int res;
+ if ((res = initialize_channel_pvt(wc, ENCODER, &wc->encoders))) {
+ return res;
+ }
+ if ((res = initialize_transcoder(wc,
+ DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW,
+ complexfmts,
+ wc->encoders,
+ &wc->uencode)))
+ {
+ return res;
+ }
+ sprintf(wc->uencode->name, "DTE Encoder");
+ return res;
+}
+
+static int
+initialize_decoders(struct wcdte *wc, unsigned int complexfmts)
+{
+ int res;
+ if ((res = initialize_channel_pvt(wc, DECODER, &wc->decoders))) {
+ return res;
+ }
+ if ((res = initialize_transcoder(wc,
+ complexfmts,
+ DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW,
+ wc->decoders,
+ &wc->udecode)))
+ {
+ return res;
+ }
+
+ sprintf(wc->udecode->name, "DTE Decoder");
+ return res;
+}
+
+static void
+wctc4xxp_send_commands(struct wcdte *wc, struct list_head *to_send)
+{
+ struct tcb *cmd;
+ while (!list_empty(to_send)) {
+ cmd = container_of(to_send->next, struct tcb, node);
+ list_del_init(&cmd->node);
+ wctc4xxp_transmit_cmd(wc, cmd);
+ }
+}
+
+static void
+wctc4xxp_watchdog(unsigned long data)
+{
+ struct wcdte *wc = (struct wcdte *)data;
+ struct tcb *cmd, *temp;
+ LIST_HEAD(cmds_to_retry);
+ const int MAX_RETRIES = 5;
+
+ spin_lock(&wc->cmd_list_lock);
+ /* Go through the list of messages that are waiting for responses from
+ * the DTE, and complete or retry any that have timed out. */
+ list_for_each_entry_safe(cmd, temp, &wc->waiting_for_response_list, node) {
+ if (time_after(jiffies, cmd->timeout)) {
+ if (++cmd->retries > MAX_RETRIES) {
+ if (!(cmd->flags & TX_COMPLETE)) {
+ set_bit(DTE_SHUTDOWN, &wc->flags);
+ spin_unlock(&wc->cmd_list_lock);
+ wctc4xxp_stop_dma(wc);
+ DTE_PRINTK(ERR, "Board malfunctioning. Halting operation.\n");
+ return;
+ }
+ /* ERROR: We've retried the command and haven't
+ * received the ACK or the response. */
+ cmd->flags |= DTE_CMD_TIMEOUT;
+ list_del_init(&cmd->node);
+ complete(&cmd->complete);
+ } else if (cmd->flags & TX_COMPLETE) {
+ /* Move this to the local list because we're
+ * going to resend it once we free the locks */
+ list_move_tail(&cmd->node, &cmds_to_retry);
+ } else {
+ /* The command is still sitting on the tx
+ * descriptor ring. We don't want to move it
+ * off any lists, lets just reset the timeout
+ * and tell the hardware to look for another
+ * command . */
+ DTE_PRINTK(WARNING, "Retrying command that was " \
+ "still on descriptor list.\n");
+ cmd->timeout = jiffies + HZ/4;
+ wctc4xxp_transmit_demand_poll(wc);
+ }
+ }
+ }
+ spin_unlock(&wc->cmd_list_lock);
+ wctc4xxp_send_commands(wc, &cmds_to_retry);
+}
+
+/**
+ * Insert an struct wcdte on the global list in sorted order
+ *
+ */
+static int __devinit
+wctc4xxp_add_to_device_list(struct wcdte *wc)
+{
+ struct wcdte *cur;
+ int pos = 0;
+ INIT_LIST_HEAD(&wc->node);
+ spin_lock(&wctc4xxp_list_lock);
+ list_for_each_entry(cur, &wctc4xxp_list, node) {
+ if (cur->pos != pos) {
+ /* Add the new entry before the one here */
+ list_add_tail(&wc->node, &wctc4xxp_list);
+ break;
+ }
+ else {
+ ++pos;
+ }
+ }
+ spin_unlock(&wctc4xxp_list_lock);
+ return pos;
+}
+
+struct wctc4xxp_desc {
+ const char *short_name;
+ const char *long_name;
+ int flags;
+};
+
+static struct wctc4xxp_desc wctc400p = {
+ .short_name = "tc400b",
+ .long_name = "Wildcard TC400P+TC400M",
+ .flags = 0,
+};
+
+static struct wctc4xxp_desc wctce400 = {
+ .short_name = "tce400",
+ .long_name = "Wildcard TCE400+TC400M",
+ .flags = 0,
+};
+
+static int __devinit
+wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res, reg, position_on_list;
+ struct wcdte *wc = NULL;
+ struct wctc4xxp_desc *d = (struct wctc4xxp_desc *)ent->driver_data;
+ unsigned char g729_numchannels, g723_numchannels, min_numchannels;
+ unsigned char wctc4xxp_firmware_ver, wctc4xxp_firmware_ver_minor;
+ unsigned int complexfmts;
struct firmware embedded_firmware;
const struct firmware *firmware = &embedded_firmware;
#if !defined(HOTPLUG_FIRMWARE)
@@ -1667,356 +2915,368 @@ static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_devic
static const char tc400m_firmware[] = "dahdi-fw-tc400m.bin";
#endif
- if (!initd_ifaces) {
- memset((void *)ifaces,0,(sizeof(struct wcdte *))*WC_MAX_IFACES);
- initd_ifaces=1;
+ /* ------------------------------------------------------------------
+ * Setup the pure software constructs internal to this driver.
+ * --------------------------------------------------------------- */
+
+ if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) {
+ return -ENOMEM;
}
- for (x=0;x<WC_MAX_IFACES;x++)
- if (!ifaces[x]) break;
- if (x >= WC_MAX_IFACES) {
- printk(KERN_NOTICE "wcdte: Too many interfaces\n");
+ memset(wc, 0, sizeof(*wc));
+
+ position_on_list = wctc4xxp_add_to_device_list(wc);
+ snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d",
+ d->short_name, position_on_list);
+ wc->iobase = pci_resource_start(pdev, 0);
+ wc->pdev = pdev;
+ wc->pos = position_on_list;
+ wc->variety = d->long_name;
+
+ init_MUTEX(&wc->chansem);
+ spin_lock_init(&wc->reglock);
+ spin_lock_init(&wc->cmd_list_lock);
+ INIT_LIST_HEAD(&wc->cmd_list);
+ INIT_LIST_HEAD(&wc->waiting_for_response_list);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK(&wc->deferred_work, deferred_work_func, wc);
+#else
+ INIT_WORK(&wc->deferred_work, deferred_work_func);
+#endif
+ DTE_PRINTK(INFO, "Attached to device at %s.\n", pci_name(wc->pdev));
+
+ /* Keep track of whether we need to free the region */
+ if (!request_region(wc->iobase, 0xff, wc->board_name)) {
+ /* \todo put in error message. */
+ DTE_PRINTK(WARNING,
+ "Failed to reserve the I/O ports for this device.\n");
return -EIO;
}
- if (pci_enable_device(pdev)) {
- res = -EIO;
- } else {
+ init_waitqueue_head(&wc->waitq);
- wc = vmalloc(sizeof(struct wcdte));
- if (wc) {
- ifaces[x] = wc;
- memset(wc, 0, sizeof(struct wcdte));
- spin_lock_init(&wc->reglock);
- sema_init(&wc->chansem, 1);
- sema_init(&wc->cmdqsem, 1);
- wc->cards = NUM_CARDS;
- wc->iobase = pci_resource_start(pdev, 0);
- wc->dev = pdev;
- wc->pos = x;
- wc->variety = d->name;
-
- wc->tdbl = 0;
- wc->rdbl = 0;
- wc->rcvflags = 0;
- wc->last_seqno = 999;
- wc->last_command_sent = 0;
- wc->last_rcommand = 0;
- wc->last_rparm1 = 0;
- wc->cmdq_wndx = 0;
- wc->cmdq_rndx = 0;
- wc->seq_num = 6;
- wc->timeout = 1 * HZ; /* 1 sec */
- wc->dsp_crashed = 0;
- wc->dumping = 0;
- wc->ztsnd_rtx = 0;
- wc->ztsnd_0010_rtx = 0;
-
- /* Keep track of whether we need to free the region */
- if (request_region(wc->iobase, 0xff, "wcdte"))
- wc->freeregion = 1;
-
- /* Allocate enought memory for all TX buffers, RX buffers, and descriptors */
- wc->writechunk = (int *)pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
- if (!wc->writechunk) {
- printk(KERN_NOTICE "wcdte error: Unable to allocate DMA-able memory\n");
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- return -ENOMEM;
- }
+ if (pci_set_dma_mask(wc->pdev, DMA_32BIT_MASK)) {
+ release_region(wc->iobase, 0xff);
+ DTE_PRINTK(WARNING, "No suitable DMA available.\n");
+ return -EIO;
+ }
- wc->readchunk = wc->writechunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
- wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+ if (!(wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL))) {
+ res = -ENOMEM;
+ goto error_exit_swinit;
+ }
- wc->descripchunk = wc->readchunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
- wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+ if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd,
+ 0xe0800000,
+ DMA_TO_DEVICE))) {
+ goto error_exit_swinit;
+ }
- /* Initialize Write/Buffers to all blank data */
- memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2);
- memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2);
+ if (!(wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL))) {
+ res = -ENOMEM;
+ goto error_exit_swinit;
+ }
- init_waitqueue_head(&wc->regq);
-
- /* Initialize the work queue */
- wc->dte_wq = create_singlethread_workqueue("tc400b");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- INIT_WORK(&wc->dte_work, dte_wque_run);
-#else
- INIT_WORK(&wc->dte_work, dte_wque_run, wc);
-#endif
+ if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0,
+ DMA_FROM_DEVICE))) {
+ goto error_exit_swinit;
+ }
#if defined(HOTPLUG_FIRMWARE)
- if ((request_firmware(&firmware, tc400m_firmware, &wc->dev->dev) != 0) ||
- !firmware) {
- printk(KERN_NOTICE "TC400M: firmware %s not available from userspace\n", tc400m_firmware);
- return -EIO;
- }
+ if ((res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev)) ||
+ !firmware) {
+ DTE_PRINTK(ERR, "Firmware %s not available from userspace. (%d)\n", tc400m_firmware, res);
+ goto error_exit_swinit;
+ }
#else
- embedded_firmware.data = _binary_dahdi_fw_tc400m_bin_start;
- embedded_firmware.size = (size_t) &_binary_dahdi_fw_tc400m_bin_size;
+ embedded_firmware.data = _binary_dahdi_fw_tc400m_bin_start;
+ embedded_firmware.size = (size_t) &_binary_dahdi_fw_tc400m_bin_size;
#endif
- dte_firmware_ver = firmware->data[0];
- dte_firmware_ver_minor = firmware->data[16];
- g729_numchannels = firmware->data[1];
- g723_numchannels = firmware->data[2];
-
- if (g723_numchannels < g729_numchannels)
- min_numchannels = g723_numchannels;
- else
- min_numchannels = g729_numchannels;
-
- /* Setup Encoders and Decoders */
-
- if (!mode || strlen(mode) < 4) {
- sprintf(wc->complexname, "G.729a / G.723.1");
- complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
- wc->numchannels = min_numchannels;
- } else if (mode[3] == '9') { /* "G.729" */
- sprintf(wc->complexname, "G.729a");
- complexfmts = DAHDI_FORMAT_G729A;
- wc->numchannels = g729_numchannels;
- } else if (mode[3] == '3') { /* "G.723.1" */
- sprintf(wc->complexname, "G.723.1");
- complexfmts = DAHDI_FORMAT_G723_1;
- wc->numchannels = g723_numchannels;
- } else {
- sprintf(wc->complexname, "G.729a / G.723.1");
- complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
- wc->numchannels = min_numchannels;
- }
-
- uencode = dahdi_transcoder_alloc(wc->numchannels);
- udecode = dahdi_transcoder_alloc(wc->numchannels);
- encoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
- decoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
- memset(encoders, 0, sizeof(struct dte_state) * wc->numchannels);
- memset(decoders, 0, sizeof(struct dte_state) * wc->numchannels);
- if (!uencode || !udecode || !encoders || !decoders) {
- if (uencode)
- dahdi_transcoder_free(uencode);
- if (udecode)
- dahdi_transcoder_free(udecode);
- if (encoders)
- vfree(encoders);
- if (decoders)
- vfree(decoders);
- return -ENOMEM;
- }
- sprintf(udecode->name, "DTE Decoder");
- sprintf(uencode->name, "DTE Encoder");
-
- udecode->srcfmts = uencode->dstfmts = complexfmts;
- udecode->dstfmts = uencode->srcfmts = DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW;
-
- udecode->operation = uencode->operation = dte_operation;
-
- for (x=0;x<wc->numchannels;x++) {
- dte_init_state(encoders + x, 1, x, wc);
- encoders[x].encoder = 1;
- decoders[x].encoder = 0;
- dte_init_state(decoders + x, 0, x, wc);
- uencode->channels[x].pvt = encoders + x;
- udecode->channels[x].pvt = decoders + x;
- }
-
- wc->uencode = uencode;
- wc->udecode = udecode;
-
- dahdi_transcoder_register(uencode);
- dahdi_transcoder_register(udecode);
+ wctc4xxp_firmware_ver = firmware->data[0];
+ wctc4xxp_firmware_ver_minor = firmware->data[16];
+ g729_numchannels = firmware->data[1];
+ g723_numchannels = firmware->data[2];
+
+ min_numchannels = min(g723_numchannels, g729_numchannels);
+
+ if (!mode || strlen(mode) < 4) {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ } else if (mode[3] == '9') { /* "G.729" */
+ sprintf(wc->complexname, "G.729a");
+ complexfmts = DAHDI_FORMAT_G729A;
+ wc->numchannels = g729_numchannels;
+ } else if (mode[3] == '3') { /* "G.723.1" */
+ sprintf(wc->complexname, "G.723.1");
+ complexfmts = DAHDI_FORMAT_G723_1;
+ wc->numchannels = g723_numchannels;
+ } else {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ }
- printk(KERN_INFO "DAHDI DTE (%s) Transcoder support LOADED (firm ver = %d.%d)\n", wc->complexname, dte_firmware_ver, dte_firmware_ver_minor);
+ if ((res = initialize_encoders(wc, complexfmts))) {
+ goto error_exit_swinit;
+ }
+ if ((res = initialize_decoders(wc, complexfmts))) {
+ goto error_exit_swinit;
+ }
+
+ if (DTE_DEBUG_NETWORK_IF & debug) {
+ if ((res = wctc4xxp_net_register(wc))) {
+ goto error_exit_swinit;
+ }
+ }
+ setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc);
- /* Enable bus mastering */
- pci_set_master(pdev);
+ /* ------------------------------------------------------------------
+ * Load the firmware and start the DTE.
+ * --------------------------------------------------------------- */
- /* Keep track of which device we are */
- pci_set_drvdata(pdev, wc);
+ if ((res = pci_enable_device(pdev))) {
+ DTE_PRINTK(ERR, "Failed to enable device.\n");
+ goto error_exit_swinit;;
+ }
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, wc);
+ if ((res = request_irq(pdev->irq, wctc4xxp_interrupt, DAHDI_IRQ_SHARED, wc->board_name, wc))) {
+ DTE_PRINTK(ERR, "Unable to request IRQ %d\n", pdev->irq);
+ if (firmware != &embedded_firmware) {
+ release_firmware(firmware);
+ }
+ goto error_exit_hwinit;
+ }
+ if ((res = wctc4xxp_hardware_init(wc))) {
+ if (firmware != &embedded_firmware) {
+ release_firmware(firmware);
+ }
+ goto error_exit_hwinit;
+ }
+ wctc4xxp_enable_interrupts(wc);
+ wctc4xxp_start_dma(wc);
+ res = wctc4xxp_boot_processor(wc, firmware);
+ if (firmware != &embedded_firmware) {
+ release_firmware(firmware);
+ }
+ if (res) {
+ goto error_exit_hwinit;
+ }
- if (request_irq(pdev->irq, wcdte_interrupt, DAHDI_IRQ_SHARED, "tc400b", wc)) {
- printk(KERN_NOTICE "wcdte error: Unable to request IRQ %d\n", pdev->irq);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- vfree(wc);
- return -EIO;
- }
+ if ((res = wctc4xxp_setup_channels(wc))) {
+ goto error_exit_hwinit;
+ }
+ /* \todo Read firmware version directly from tc400b.*/
+ DTE_PRINTK(INFO, "(%s) Transcoder support LOADED " \
+ "(firm ver = %d.%d)\n", wc->complexname, wctc4xxp_firmware_ver,
+ wctc4xxp_firmware_ver_minor);
- if (wcdte_hardware_init(wc)) {
- /* Set Reset Low */
- wcdte_stop_dma(wc);
- /* Free Resources */
- free_irq(pdev->irq, wc);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- vfree(wc);
- return -EIO;
+ reg = wctc4xxp_getctl(wc, 0x00fc);
- }
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "debug: (post-boot) Reg fc is %08x\n", reg);
+
+ DTE_PRINTK(INFO, "Installed a Wildcard TC: %s \n", wc->variety);
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "Operating in DEBUG mode.\n");
+ dahdi_transcoder_register(wc->uencode);
+ dahdi_transcoder_register(wc->udecode);
- /* Enable interrupts */
- wcdte_enable_interrupts(wc);
-
- /* Start DMA */
- wcdte_start_dma(wc);
-
- if (wcdte_boot_processor(wc,firmware,1)) {
- if (firmware != &embedded_firmware)
- release_firmware(firmware);
-
- /* Set Reset Low */
- wcdte_stop_dma(wc);
- /* Free Resources */
- free_irq(pdev->irq, wc);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- vfree(wc);
- return -EIO;
- }
- if (firmware != &embedded_firmware)
- release_firmware(firmware);
-
- if (wcdte_setup_channels(wc)) {
- /* Set Reset Low */
- wcdte_stop_dma(wc);
- /* Free Resources */
- free_irq(pdev->irq, wc);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- vfree(wc);
- return -EIO;
- }
+ return 0;
- reg = wcdte_getctl(wc, 0x00fc);
- if (debug)
- printk(KERN_DEBUG "wcdte debug: (post-boot) Reg fc is %08x\n", reg);
-
- printk(KERN_INFO "Found and successfully installed a Wildcard TC: %s \n", wc->variety);
- if (debug) {
- printk(KERN_DEBUG "TC400B operating in DEBUG mode\n");
- printk(KERN_DEBUG "debug_des = %d, debug_des_cnt = %d, force_alert = %d,\n debug_notimeout = %d, debug_packets = %d\n",
- debug_des, debug_des_cnt, force_alert, debug_notimeout, debug_packets);
- }
- res = 0;
- } else
- res = -ENOMEM;
+error_exit_hwinit:
+ wctc4xxp_stop_dma(wc);
+ wctc4xxp_cleanup_command_list(wc);
+ free_irq(pdev->irq, wc);
+ pci_set_drvdata(pdev, NULL);
+error_exit_swinit:
+ wctc4xxp_net_unregister(wc);
+ if (wc->encoders) kfree(wc->encoders);
+ if (wc->decoders) kfree(wc->decoders);
+ if (wc->uencode) dahdi_transcoder_free(wc->uencode);
+ if (wc->udecode) dahdi_transcoder_free(wc->udecode);
+ if (wc->txd) {
+ if (wc->txd->desc) {
+ wctc4xxp_cleanup_descriptor_ring(wc->txd);
+ }
+ kfree(wc->txd);
}
- return res;
+ if (wc->rxd) {
+ if (wc->rxd && wc->rxd->desc) {
+ wctc4xxp_cleanup_descriptor_ring(wc->rxd);
+ }
+ kfree(wc->rxd);
+ }
+ release_region(wc->iobase, 0xff);
+ spin_lock(&wctc4xxp_list_lock);
+ list_del(&wc->node);
+ spin_unlock(&wctc4xxp_list_lock);
+ kfree(wc);
+ return res;
}
-static void wcdte_release(struct wcdte *wc)
+static void wctc4xxp_cleanup_channels(struct wcdte *wc)
{
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- vfree(wc);
+ int i;
+ struct dahdi_transcoder_channel *dtc_en, *dtc_de;
+ struct channel_pvt *cpvt;
+
+ for(i = 0; i < wc->numchannels; i++) {
+ dtc_en = &(wc->uencode->channels[i]);
+ cpvt = dtc_en->pvt;
+ wctc4xxp_cleanup_channel_private(wc, cpvt);
+
+ dtc_de = &(wc->udecode->channels[i]);
+ cpvt = dtc_de->pvt;
+ wctc4xxp_cleanup_channel_private(wc, cpvt);
+ }
}
-static void __devexit wcdte_remove_one(struct pci_dev *pdev)
+static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev)
{
int i;
struct wcdte *wc = pci_get_drvdata(pdev);
- struct dahdi_transcoder_channel *ztc_en, *ztc_de;
- struct dte_state *st_en, *st_de;
-
- if (wc) {
- if (debug)
- {
- printk(KERN_DEBUG "wcdte debug: wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx);
- printk(KERN_DEBUG "wcdte debug: wc->ztsnd_0010_rtx = %d\n", wc->ztsnd_0010_rtx);
-
- for(i = 0; i < wc->numchannels; i++)
- {
- ztc_en = &(wc->uencode->channels[i]);
- st_en = ztc_en->pvt;
-
- ztc_de = &(wc->udecode->channels[i]);
- st_de = ztc_de->pvt;
-
- printk(KERN_DEBUG "wcdte debug: en[%d] snt = %d, rcv = %d [%d]\n", i, st_en->packets_sent, st_en->packets_received, st_en->packets_sent - st_en->packets_received);
- printk(KERN_DEBUG "wcdte debug: de[%d] snt = %d, rcv = %d [%d]\n", i, st_de->packets_sent, st_de->packets_received, st_de->packets_sent - st_de->packets_received);
- }
+ struct dahdi_transcoder_channel *dtc_en, *dtc_de;
+ struct channel_pvt *cpvt;
+
+ if (!wc) {
+ /* \todo print warning message here. */
+ return;
+ }
+
+ spin_lock(&wctc4xxp_list_lock);
+ list_del(&wc->node);
+ spin_unlock(&wctc4xxp_list_lock);
+
+ set_bit(DTE_SHUTDOWN, &wc->flags);
+ if (del_timer_sync(&wc->watchdog)) {
+ /* Just delete the timer twice in case the timer had already
+ * checked DTE_SHUTDOWN and rescheduled itself the first time.
+ */
+ del_timer_sync(&wc->watchdog);
+ }
+
+ wctc4xxp_net_unregister(wc);
+
+ if (debug) {
+ for(i = 0; i < wc->numchannels; i++) {
+ dtc_en = &(wc->uencode->channels[i]);
+ cpvt = dtc_en->pvt;
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "encoder[%d] snt = %d, rcv = %d [%d]\n", i,
+ atomic_read(&cpvt->stats.packets_sent),
+ atomic_read(&cpvt->stats.packets_received),
+ atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received));
+
+ dtc_de = &(wc->udecode->channels[i]);
+ cpvt = dtc_de->pvt;
+ DTE_DEBUG(DTE_DEBUG_GENERAL,
+ "decoder[%d] snt = %d, rcv = %d [%d]\n", i,
+ atomic_read(&cpvt->stats.packets_sent),
+ atomic_read(&cpvt->stats.packets_received),
+ atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received));
}
+ }
+
+ /* Stop any DMA */
+ wctc4xxp_stop_dma(wc);
- dahdi_transcoder_unregister(wc->udecode);
- dahdi_transcoder_unregister(wc->uencode);
- dahdi_transcoder_free(wc->uencode);
- dahdi_transcoder_free(wc->udecode);
- vfree(wc->uencode->channels[0].pvt);
- vfree(wc->udecode->channels[0].pvt);
+ /* In case hardware is still there */
+ wctc4xxp_disable_interrupts(wc);
- /* Stop any DMA */
- wcdte_stop_dma(wc);
+ free_irq(pdev->irq, wc);
- /* In case hardware is still there */
- wcdte_disable_interrupts(wc);
+ /* There isn't anything that would run in the workqueue that will wait
+ * on an interrupt. */
- /* Kill workqueue */
- destroy_workqueue(wc->dte_wq);
-
- /* Immediately free resources */
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- free_irq(pdev->irq, wc);
+ dahdi_transcoder_unregister(wc->udecode);
+ dahdi_transcoder_unregister(wc->uencode);
- /* Release span, possibly delayed */
- wcdte_release(wc);
+ /* Free Resources */
+ release_region(wc->iobase, 0xff);
+ spin_lock_bh(&wc->cmd_list_lock);
+ if (wc->txd) {
+ if (wc->txd->desc) wctc4xxp_cleanup_descriptor_ring(wc->txd);
+ kfree(wc->txd);
}
+ if (wc->rxd) {
+ if (wc->rxd && wc->rxd->desc) wctc4xxp_cleanup_descriptor_ring(wc->rxd);
+ kfree(wc->rxd);
+ }
+ spin_unlock_bh(&wc->cmd_list_lock);
+ wctc4xxp_cleanup_command_list(wc);
+ wctc4xxp_cleanup_channels(wc);
+
+ pci_set_drvdata(pdev, NULL);
+
+ dahdi_transcoder_free(wc->uencode);
+ dahdi_transcoder_free(wc->udecode);
+ kfree(wc->encoders);
+ kfree(wc->decoders);
+ kfree(wc);
}
-static struct pci_device_id wcdte_pci_tbl[] = {
-#ifndef USE_TEST_HW
+static struct pci_device_id wctc4xxp_pci_tbl[] = {
{ 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */
{ 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */
-#else
- { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* reference board */
-#endif
{ 0 }
};
-MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl);
+MODULE_DEVICE_TABLE(pci, wctc4xxp_pci_tbl);
-static struct pci_driver wcdte_driver = {
+static struct pci_driver wctc4xxp_driver = {
name: "wctc4xxp",
- probe: wcdte_init_one,
- remove: __devexit_p(wcdte_remove_one),
+ probe: wctc4xxp_init_one,
+ remove: __devexit_p(wctc4xxp_remove_one),
suspend: NULL,
resume: NULL,
- id_table: wcdte_pci_tbl,
+ id_table: wctc4xxp_pci_tbl,
};
-int ztdte_init(void)
+int __init wctc4xxp_init(void)
{
int res;
-
- res = dahdi_pci_module(&wcdte_driver);
+# ifndef CONFIG_WCDTE_NETWORK_IF
+ if (debug & (DTE_DEBUG_NETWORK_IF|DTE_DEBUG_NETWORK_EARLY)) {
+ printk(KERN_WARNING "%s: The Network interface was not compiled into the driver.\n", THIS_MODULE->name);
+ debug &= ~(DTE_DEBUG_NETWORK_IF|DTE_DEBUG_NETWORK_EARLY);
+ }
+# endif
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+ cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+# else
+ cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+# endif
+
+ if (!cmd_cache) {
+ return -ENOMEM;
+ }
+ spin_lock_init(&wctc4xxp_list_lock);
+ INIT_LIST_HEAD(&wctc4xxp_list);
+ res = dahdi_pci_module(&wctc4xxp_driver);
if (res)
return -ENODEV;
return 0;
}
-void ztdte_cleanup(void)
+void __exit wctc4xxp_cleanup(void)
{
- pci_unregister_driver(&wcdte_driver);
+ WARN_ON(!list_empty(&wctc4xxp_list));
+ pci_unregister_driver(&wctc4xxp_driver);
+ kmem_cache_destroy(cmd_cache);
}
module_param(debug, int, S_IRUGO | S_IWUSR);
-module_param(debug_des, int, S_IRUGO | S_IWUSR);
-module_param(debug_des_cnt, int, S_IRUGO | S_IWUSR);
-module_param(debug_notimeout, int, S_IRUGO | S_IWUSR);
-module_param(force_alert, int, S_IRUGO | S_IWUSR);
-module_param(mode, charp, S_IRUGO | S_IWUSR);
-
MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver");
-MODULE_AUTHOR("John Sloan <jsloan@digium.com>");
-MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
-module_init(ztdte_init);
-module_exit(ztdte_cleanup);
+module_init(wctc4xxp_init);
+module_exit(wctc4xxp_cleanup);
diff --git a/drivers/dahdi/wctc4xxp/codec_test.c b/drivers/dahdi/wctc4xxp/codec_test.c
deleted file mode 100644
index a4e1cdc..0000000
--- a/drivers/dahdi/wctc4xxp/codec_test.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Wildcard TC400B Digium Transcoder Engine Interface Driver for DAHDI Telephony interface test tool.
- *
- * Written by Matt O'Gorman <mogorman@digium.com>
- *
- * Copyright (C) 2006-2007, Digium, Inc.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <dahdi/kernel.h>
-
-#define MAX_CARDS_TO_TEST 6
-#define MAX_CHANNELS_PER_CARD 96
-
-#define AST_FORMAT_ULAW (1 << 2)
-#define AST_FORMAT_G729A (1 << 8)
-
-#define AST_FRIENDLY_OFFSET 64
-
-static int debug = 0;
-
-static unsigned char ulaw_slin_ex[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char g729a_expected[] = {
- 0xE9, 0x88, 0x4C, 0xA0, 0x00, 0xFA, 0xDD, 0xA2, 0x06, 0x2D,
- 0x69, 0x88, 0x00, 0x60, 0x68, 0xD5, 0x9E, 0x20, 0x80, 0x50
-};
-
-
-struct format_map {
- unsigned int map[32][32];
-};
-
-
-struct tcpvt {
- int fd;
- int fake;
- int inuse;
- struct dahdi_transcode_header *hdr;
-// struct ast_frame f;
-};
-
-struct tctest_info {
- int numcards;
- int numchans[MAX_CARDS_TO_TEST];
- int total_chans;
- int errors;
- int overcnt_error; /* Too many cards found */
- int undercnt_error; /* Too few cards found */
- int timeout_error[MAX_CARDS_TO_TEST];
- int data_error[MAX_CARDS_TO_TEST];
- int numcards_werrors;
-};
-
-
-static int find_transcoders(struct tctest_info *tctest_info)
-{
- struct dahdi_transcode_info info = { 0, };
- int fd, res;
-
- if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
- printf("Warning: No DAHDI transcoder support!\n");
- return 0;
- }
-
- tctest_info->total_chans = 0;
- info.op = DAHDI_TCOP_GETINFO;
- for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TRANSCODE_OP, &info)); info.tcnum++) {
- if (debug)
- printf("Found transcoder %d, '%s' with %d channels.\n", info.tcnum, info.name, info.numchannels);
- if ((info.tcnum % 2) == 0)
- {
- tctest_info->numchans[info.tcnum/2] = info.numchannels;
- tctest_info->total_chans += info.numchannels;
- }
- }
- tctest_info->numcards = info.tcnum / 2;
-
- close(fd);
- if (!info.tcnum)
- printf("No hardware transcoders found.\n");
- return 0;
-}
-
-
-static int open_transcoder(struct tcpvt *ztp, int dest, int source)
-{
- int fd;
- unsigned int x = DAHDI_TCOP_ALLOCATE;
- struct dahdi_transcode_header *hdr;
- int flags;
-
- if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0)
- return -1;
- flags = fcntl(fd, F_GETFL);
- if (flags > - 1) {
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
- printf("Could not set non-block mode!\n");
- }
-
- if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- printf("Memory Map failed for transcoding (%s)\n", strerror(errno));
- close(fd);
-
- return -1;
- }
-
- if (hdr->magic != DAHDI_TRANSCODE_MAGIC) {
- printf("Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic);
- munmap(hdr, sizeof(*hdr));
- close(fd);
-
- return -1;
- }
-
- hdr->srcfmt = source;
- hdr->dstfmt = dest;
-
- if (ioctl(fd, DAHDI_TRANSCODE_OP, &x)) {
- printf("Unable to attach transcoder: %s\n", strerror(errno));
- munmap(hdr, sizeof(*hdr));
- close(fd);
-
- return -1;
- }
-
- ztp->fd = fd;
- ztp->hdr = hdr;
-
- return 0;
-}
-
-
-static void close_transcoder(struct tcpvt *ztp)
-{
- unsigned int x;
-
- x = DAHDI_TCOP_RELEASE;
- if (ioctl(ztp->fd, DAHDI_TRANSCODE_OP, &x))
- printf("Failed to release transcoder channel: %s\n", strerror(errno));
-
- munmap(ztp->hdr, sizeof(*ztp->hdr));
- close(ztp->fd);
-}
-
-
-static int encode_packet(struct tcpvt *ztp, unsigned char *packet_in, unsigned char *packet_out)
-{
- struct dahdi_transcode_header *hdr = ztp->hdr;
- unsigned int x;
-
- hdr->srcoffset = 0;
-
- memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, packet_in, 160);
- hdr->srclen += 160;
-
-
- hdr->dstoffset = AST_FRIENDLY_OFFSET;
- x = DAHDI_TCOP_TRANSCODE;
- if (ioctl(ztp->fd, DAHDI_TRANSCODE_OP, &x))
- printf("Failed to transcode: %s\n", strerror(errno));
-
- usleep(20000);
- if (hdr->dstlen)
- {
- memcpy(packet_out, hdr->dstdata + hdr->dstoffset, hdr->dstlen);
- return 0;
- }
- else
- return -1;
-}
-
-
-static void print_failed()
-{
- printf("______ ___ _____ _ _____ ______\n");
- printf("| ___| / _ \\ |_ _| | | | ___| | _ \\\n");
- printf("| |_ / /_\\ \\ | | | | | |__ | | | |\n");
- printf("| _| | _ | | | | | | __| | | | |\n");
- printf("| | | | | | _| |_ | |____ | |___ | |/ /\n");
- printf("\\_| \\_| |_/ \\___/ \\_____/ \\____/ |___/ \n");
-}
-
-
-int main(int argc, char *argv[])
-{
- int arg1, arg2, i, j, card_testing, chan_testing;
- struct tcpvt ztp[MAX_CHANNELS_PER_CARD * MAX_CARDS_TO_TEST];
- unsigned char packet_out[200];
- struct tctest_info tctest_info;
-
- memset(&tctest_info, 0, sizeof(tctest_info));
-
- if ((argc < 2) || (argc > 3))
- {
- printf("codec_test requires one argument.\n");
- printf(" arg1 = number of cards to test\n");
- return -1;
- }
-
- if (argc == 2)
- sscanf(argv[1], "%d", &arg1);
- else if (argc == 3)
- {
- sscanf(argv[1], "%d %d", &arg1, &arg2);
- debug = arg2;
- }
-
- printf("Beginning test of %d TC400B cards\n", arg1);
-
-
- /* Search for TC400Bs */
- find_transcoders(&tctest_info);
-
- if (tctest_info.numcards > arg1)
- {
- tctest_info.errors++;
- tctest_info.overcnt_error = 1;
- }
- if (tctest_info.numcards < arg1)
- {
- tctest_info.errors++;
- tctest_info.undercnt_error = 1;
- }
-
- if (tctest_info.errors == 0)
- {
- /* Begin testing transcoder channels */
- for (card_testing = 0; card_testing < tctest_info.numcards; card_testing++)
- {
- tctest_info.data_error[card_testing] = 0;
- tctest_info.timeout_error[card_testing] = 0;
- for (chan_testing = 0; chan_testing < tctest_info.numchans[card_testing]; chan_testing++)
- {
- i = chan_testing;
- for(j = 0; j < card_testing; j++)
- i += tctest_info.numchans[j];
-
- open_transcoder(&ztp[i], AST_FORMAT_G729A, AST_FORMAT_ULAW);
-
- if ((tctest_info.timeout_error[card_testing] = encode_packet(&ztp[i], ulaw_slin_ex, packet_out) == -1))
- tctest_info.errors++;
-
- if (memcmp(g729a_expected, packet_out, 20) != 0)
- {
- tctest_info.errors++;
- tctest_info.data_error[card_testing] += 1;
- }
- }
- if ( (tctest_info.data_error[card_testing]) || (tctest_info.timeout_error[card_testing]) )
- tctest_info.numcards_werrors++;
- }
-
- for (i = 0; i < tctest_info.total_chans; i++)
- close_transcoder(&ztp[i]);
- }
-
- if (debug)
- {
- printf("\n\n");
- printf("tctest_info.errors = %d\n", tctest_info.errors);
- printf("tctest_info.overcnt_error = %d\n", tctest_info.overcnt_error);
- printf("tctest_info.undercnt_error = %d\n", tctest_info.undercnt_error);
- printf("tctest_info.numcards_werrors = %d\n", tctest_info.numcards_werrors);
-
- for (i = 0; i < tctest_info.numcards; i++)
- {
- printf("tctest_info.data_error[%d] = %d\n", i, tctest_info.data_error[i]);
- printf("tctest_info.timeout_error[%d] = %d\n", i, tctest_info.timeout_error[i]);
- }
- }
-
- if (tctest_info.errors)
- {
- printf("\n\n\n");
- if (tctest_info.numcards_werrors)
- printf("%d of %d cards\n", tctest_info.numcards_werrors, tctest_info.numcards);
- print_failed();
- if (tctest_info.overcnt_error)
- printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1);
- if (tctest_info.undercnt_error)
- printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1);
- printf("\n\n\n");
- }
- else
- printf("%d of %d cards PASSED\n", tctest_info.numcards - tctest_info.numcards_werrors, tctest_info.numcards);
-
- return 0;
-}