summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-08-14 01:57:01 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-08-14 01:57:01 +0000
commitc990a6d6901cc88a727578ab95a85280ec9a710d (patch)
tree252ca25de7a51b22ae82fd2c5298ed303d9af356
parent3001c9701d58c20c8f5b574cb34db89171191981 (diff)
backport new transcoder interface and driver from DAHDI
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4483 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--kernel/wctc4xxp/Kbuild2
-rw-r--r--kernel/wctc4xxp/Makefile10
-rw-r--r--kernel/wctc4xxp/base.c4146
-rw-r--r--kernel/wctc4xxp/codec_test.c329
-rw-r--r--kernel/zaptel-base.c50
-rw-r--r--kernel/zaptel.h146
-rw-r--r--kernel/zttranscode.c564
7 files changed, 3080 insertions, 2167 deletions
diff --git a/kernel/wctc4xxp/Kbuild b/kernel/wctc4xxp/Kbuild
index 353290f..5783b14 100644
--- a/kernel/wctc4xxp/Kbuild
+++ b/kernel/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)/zaptel-fw-tc400m.o
diff --git a/kernel/wctc4xxp/Makefile b/kernel/wctc4xxp/Makefile
index 725abc4..56453cb 100644
--- a/kernel/wctc4xxp/Makefile
+++ b/kernel/wctc4xxp/Makefile
@@ -3,14 +3,4 @@ ifneq ($(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 ../zaptel.h
- $(CC) -o $@ $< $(CFLAGS)
-
-clean:
- rm -rf codec_test
endif
diff --git a/kernel/wctc4xxp/base.c b/kernel/wctc4xxp/base.c
index 90642b8..2cf24d7 100644
--- a/kernel/wctc4xxp/base.c
+++ b/kernel/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.
*
@@ -26,86 +24,154 @@
#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>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
-#include "zaptel.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 <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
-#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 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 */
+#include "zaptel.h"
-#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
+/* COMPILE TIME OPTIONS =================================================== */
-#define SFRAME_SIZE MAX_COMMAND_LEN
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET 2
-#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, \
@@ -181,17 +247,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, \
@@ -242,1119 +317,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 zt_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("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 zt_transcoder *uencode;
struct zt_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);
+}
+
+#if 1
+ /* \todo This macro is a candidate for removal. It's still here because of
+ * how the commands are passed to this zt_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_zapfmt_to_dtefmt(unsigned int fmt)
+{
+ u8 pt;
+
+ switch(fmt) {
+ case ZT_FORMAT_G723_1:
+ pt = DTE_FORMAT_G723_1;
+ break;
+ case ZT_FORMAT_ULAW:
+ pt = DTE_FORMAT_ULAW;
+ break;
+ case ZT_FORMAT_ALAW:
+ pt = DTE_FORMAT_ALAW;
+ break;
+ case ZT_FORMAT_G729A:
+ pt = DTE_FORMAT_G729A;
+ break;
+ default:
+ pt = DTE_FORMAT_UNDEF;
+ break;
+ }
-static struct wcdte *ifaces[WC_MAX_IFACES];
+ 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;
+}
-/*
- * 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.
+/**
+ * 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 zt_transcoder *uencode;
-static struct zt_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);
+
+ count = wctc4xxp_net_receive(wc, quota);
-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);
+ *budget -= count;
+ netdev->quota -= count;
-static int __dump_descriptors(struct wcdte *wc)
+ 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("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("->");
- else
- printk(" ");
- 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("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("->");
- else
- printk(" ");
- 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 zt_tc_sanitycheck(struct zt_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 ZT_FORMAT_G723_1:
- pt = DTE_FORMAT_G723_1;
- break;
- case ZT_FORMAT_ULAW:
- pt = DTE_FORMAT_ULAW;
- break;
- case ZT_FORMAT_ALAW:
- pt = DTE_FORMAT_ALAW;
- break;
- case ZT_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;
}
- return(pt);
+ 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);
+ }
+
+ d->des1 |= cpu_to_le32(END_OF_RING);
+ dr->direction = direction;
+ spin_lock_init(&dr->lock);
+ return 0;
}
-static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+#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 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("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 zt_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_zapfmt_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);
+}
+
+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);
+ }
+}
- wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS;
+/**
+ * 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);
+}
- return(0);
+static void
+wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd)
+{
+ 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 inline int transmit_demand(struct wcdte *wc)
+static void
+wctc4xxp_remove_from_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_del_init(&cmd->node);
+ spin_unlock_bh(&wc->cmd_list_lock);
}
-static int dte_operation(struct zt_transcoder_channel *ztc, int op)
-{
- struct zt_transcoder_channel *compl_ztc;
- struct dte_state *st = ztc->pvt, *compl_st;
- struct zt_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 ZT_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_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 ZT_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 & ZT_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 ZT_TCOP_TRANSCODE:
- if ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
- || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
- || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) )
- {
- do
- {
- chars = (unsigned char *)(zth->srcdata + zth->srcoffset);
-
- if ((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) {
- if (zth->dstfmt == ZT_FORMAT_G729A) {
- inbytes = G729_SAMPLES;
- timestamp_inc = G729_SAMPLES;
- } else if (zth->dstfmt == ZT_FORMAT_G723_1) {
- inbytes = G723_SAMPLES;
- timestamp_inc = G723_SAMPLES;
- }
- } else if (zth->srcfmt == ZT_FORMAT_G729A) {
- inbytes = G729_BYTES;
- timestamp_inc = G729_SAMPLES;
- } else if (zth->srcfmt == ZT_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("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 == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
- || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
- || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) );
+ cpvt->ssrc = 0x78;
+
+ cpvt->timeslot_in_num = channel* 2;
+ cpvt->timeslot_out_num = channel * 2;
- } else {
- zt_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 zt_transcoder_channel *dtc)
+{
+ int index;
+ struct channel_pvt *cpvt = dtc->pvt;
+ struct zt_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(zt_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;
+ zt_tc_set_built(compl_dtc);
+ wctc4xxp_cleanup_channel_private(wc, compl_cpvt);
+
+ return 0;
+}
+
+static int
+do_channel_allocate(struct zt_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... */
+ zt_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_zapfmt_to_dtefmt(dtc->srcfmt);
+ wctc4xxp_dstfmt = wctc4xxp_zapfmt_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 */
+ zt_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);
+ zt_transcoder_alert(dtc);
return res;
}
-static void wcdte_stop_dma(struct wcdte *wc);
+static int
+wctc4xxp_operation_allocate(struct zt_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 (zt_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 zt_transcoder_channel *dtc)
{
- volatile unsigned char *readchunk;
- struct zt_transcoder_channel *ztc = NULL;
- struct zt_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 zt_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 (!zt_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 (zt_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 */
+ zt_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 */
+ zt_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 zt_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(!zt_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)) {
+ zt_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("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("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 zt_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,
+ zt_tc_is_data_waiting(dtc));
+ if (-ERESTARTSYS == ret) {
+ /* Signal interrupted the wait */
+ return -EINTR;
} else {
- if (debug)
- printk("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("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)) {
- 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("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("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("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("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 zt_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 (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_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;
- }
- zt_transcoder_alert(ztc);
- }
- else if (rcodec == 0x08) /* alaw */
- {
- if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+ if (!test_bit(ZT_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 %Zu bytes.\n", count,
+ SFRAME_SIZE - sizeof(struct rtp_packet));
+ return -EINVAL;
+ }
- } else {
- ztc->errorstatus = -EOVERFLOW;
- }
- zt_transcoder_alert(ztc);
+ if (ZT_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 (zt_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))
- {
- zt_transcoder_alert(ztc);
- }
- }
- else if (rcodec == 0x12) /* G.729a */
- {
- if (zt_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))
- {
- zt_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 inline int wcdte_check_descriptor(struct wcdte *wc) */
-static int wcdte_check_descriptor(struct wcdte *wc)
+static void
+receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
{
- int o2 = 0;
+ const struct csm_encaps_hdr *hdr = cmd->data;
- o2 += ERING_SIZE * 4;
- o2 += wc->rdbl * 4;
+ if (!(hdr->control & MESSAGE_PACKET)) {
- 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;
+ if (!(hdr->control & SUPPRESS_ACK)) {
+ wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel);
+ }
- return 1;
+ 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);
}
- return 0;
}
-static void wcdte_init_descriptors(struct wcdte *wc)
+static void
+queue_rtp_packet(struct wcdte *wc, struct tcb *cmd)
{
- 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);
+ int index;
+ struct zt_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;
+ }
+
+ 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);
+ zt_tc_set_data_waiting(dtc);
+ zt_transcoder_alert(dtc);
+ return;
+}
+
+static inline void
+wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd)
+{
+ const struct ethhdr *ethhdr = (const struct ethhdr*)(cmd->data);
+
+ 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);
+ }
+}
+
+static inline void service_dte(struct wcdte *wc)
+{
+ 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);
}
-ZAP_IRQ_HANDLER(wcdte_interrupt)
+ZAP_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("wcdte: Abnormal Interrupt: ");
+ 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("wcdte: Fatal Bus Error INT\n");
+ if ((ints & 0x00002000) && debug)
+ DTE_PRINTK(INFO, "Fatal Bus Error INT\n");
- if ((ints & 0x00000100) && debug)
- printk("wcdte: Receive Stopped INT\n");
+ if ((ints & 0x00000100) && debug)
+ DTE_PRINTK(INFO, "Receive Stopped INT\n");
- if ((ints & 0x00000080) && debug)
- printk("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("wcdte: Transmit Under-flow INT\n");
+ if ((ints & 0x00000020) && debug)
+ DTE_PRINTK(INFO, "Transmit Under-flow INT\n");
- if ((ints & 0x00000008) && debug)
- printk("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("wcdte: Transmit Descriptor Unavailable INT\n");
+ if ((ints & 0x00000004) && debug)
+ ; // printk("wcdte: Transmit Descriptor Unavailable INT\n");
- if ((ints & 0x00000002) && debug)
- printk("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);
+ pci_write_config_dword(wc->pdev, 0x0004, reg);
- wcdte_setctl(wc, 0x0000, 0xFFF88001);
-
- 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("wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret);
- return(1);
- }
- if (ret == 0)
- {
- if (debug)
- printk("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;
@@ -1363,34 +2254,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;
@@ -1398,624 +2291,991 @@ 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("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("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("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("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("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 zt_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 zt_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;
- /* Create complex channel */
- zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
- zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
- chan1 = wc->last_rparm1;
+
+ 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 simple channel */
- zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
- zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
- chan2 = wc->last_rparm1;
+ length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
+ (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;
- ztc1 = &(wc->uencode->channels[part1_id/2]);
- ztc2 = &(wc->udecode->channels[part2_id/2]);
- st1 = ztc1->pvt;
- st2 = ztc2->pvt;
+ 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);
- /* Configure complex channel */
- zt_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);
- zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+ 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);
+ 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 */
- zt_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);
- zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
-
-#ifdef QUIET_DSP
- zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
- zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
- zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
- zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
- zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
- zt_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;
+ }
- zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
- zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
- zt_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 zt_transcoder_channel *ztc1, *ztc2;
- struct dte_state *st1, *st2;
+ struct zt_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 */
- zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
- zt_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 */
- zt_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 */
- zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
- zt_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
- zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411);
- zt_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
- zt_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417);
- zt_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405);
- zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
- zt_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;
+ }
- zt_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100);
- zt_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302);
- zt_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105);
- zt_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
- zt_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;
+ }
- zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
- zt_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306);
- zt_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
- zt_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 zt_transcoder **zt)
+{
+ int chan;
+ *zt = zt_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,
+ ZT_FORMAT_ULAW | ZT_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,
+ ZT_FORMAT_ULAW | ZT_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)
- extern void _binary_zaptel_fw_tc400m_bin_size;
- extern u8 _binary_zaptel_fw_tc400m_bin_start[];
+ extern void _binary_zt_fw_tc400m_bin_size;
+ extern u8 _binary_zt_fw_tc400m_bin_start[];
#else
static const char tc400m_firmware[] = "zaptel-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("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("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("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_zaptel_fw_tc400m_bin_start;
- embedded_firmware.size = (size_t) &_binary_zaptel_fw_tc400m_bin_size;
+ embedded_firmware.data = _binary_zt_fw_tc400m_bin_start;
+ embedded_firmware.size = (size_t) &_binary_zt_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 = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
- wc->numchannels = min_numchannels;
- } else if (mode[3] == '9') { /* "G.729" */
- sprintf(wc->complexname, "G.729a");
- complexfmts = ZT_FORMAT_G729A;
- wc->numchannels = g729_numchannels;
- } else if (mode[3] == '3') { /* "G.723.1" */
- sprintf(wc->complexname, "G.723.1");
- complexfmts = ZT_FORMAT_G723_1;
- wc->numchannels = g723_numchannels;
- } else {
- sprintf(wc->complexname, "G.729a / G.723.1");
- complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
- wc->numchannels = min_numchannels;
- }
-
- uencode = zt_transcoder_alloc(wc->numchannels);
- udecode = zt_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)
- zt_transcoder_free(uencode);
- if (udecode)
- zt_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 = ZT_FORMAT_ULAW | ZT_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;
-
- zt_transcoder_register(uencode);
- zt_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 = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ } else if (mode[3] == '9') { /* "G.729" */
+ sprintf(wc->complexname, "G.729a");
+ complexfmts = ZT_FORMAT_G729A;
+ wc->numchannels = g729_numchannels;
+ } else if (mode[3] == '3') { /* "G.723.1" */
+ sprintf(wc->complexname, "G.723.1");
+ complexfmts = ZT_FORMAT_G723_1;
+ wc->numchannels = g723_numchannels;
+ } else {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ }
- printk("Zaptel 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, ZAP_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, ZAP_IRQ_SHARED, "tc400b", wc)) {
- printk("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");
+ zt_transcoder_register(wc->uencode);
+ zt_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("wcdte debug: (post-boot) Reg fc is %08x\n", reg);
-
- printk("Found and successfully installed a Wildcard TC: %s \n", wc->variety);
- if (debug) {
- printk("TC400B operating in DEBUG mode\n");
- printk("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) zt_transcoder_free(wc->uencode);
+ if (wc->udecode) zt_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 zt_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 zt_transcoder_channel *ztc_en, *ztc_de;
- struct dte_state *st_en, *st_de;
-
- if (wc) {
- if (debug)
- {
- printk("wcdte debug: wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx);
- printk("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("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("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 zt_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);
- zt_transcoder_unregister(wc->udecode);
- zt_transcoder_unregister(wc->uencode);
- zt_transcoder_free(wc->uencode);
- zt_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);
+ zt_transcoder_unregister(wc->udecode);
+ zt_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);
+
+ zt_transcoder_free(wc->uencode);
+ zt_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 = zap_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 = zap_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_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/kernel/wctc4xxp/codec_test.c b/kernel/wctc4xxp/codec_test.c
deleted file mode 100644
index a476212..0000000
--- a/kernel/wctc4xxp/codec_test.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Wilcard TC400B Digium Transcoder Engine Interface Driver for Zapata Telephony interface test tool.
- *
- * Written by Matt O'Gorman <mogorman@digium.com>
- *
- * Copyright (C) 2006-2007, Digium, Inc.
- *
- * All rights reserved.
- *
- */
-
-/*
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2 as published by the
- * Free Software Foundation. See the LICENSE file included with
- * this program for more details.
- */
-
-#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>
-#ifdef STANDALONE_ZAPATA
-#include "zaptel.h"
-#else
-#include <linux/zaptel.h>
-#endif
-
-#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 zt_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 zt_transcode_info info = { 0, };
- int fd, res;
-
- if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
- printf("Warning: No Zaptel transcoder support!\n");
- return 0;
- }
-
- tctest_info->total_chans = 0;
- info.op = ZT_TCOP_GETINFO;
- for (info.tcnum = 0; !(res = ioctl(fd, ZT_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 = ZT_TCOP_ALLOCATE;
- struct zt_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 != ZT_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, ZT_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 = ZT_TCOP_RELEASE;
- if (ioctl(ztp->fd, ZT_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 zt_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 = ZT_TCOP_TRANSCODE;
- if (ioctl(ztp->fd, ZT_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;
-}
diff --git a/kernel/zaptel-base.c b/kernel/zaptel-base.c
index 53b6f15..deeb01c 100644
--- a/kernel/zaptel-base.c
+++ b/kernel/zaptel-base.c
@@ -2579,30 +2579,29 @@ static void zt_free_pseudo(struct zt_chan *pseudo)
static int zt_open(struct inode *inode, struct file *file)
{
int unit = UNIT(file);
- int ret = -ENXIO;
+
struct zt_chan *chan;
/* Minor 0: Special "control" descriptor */
if (!unit)
return zt_ctl_open(inode, file);
if (unit == 250) {
if (!zt_transcode_fops)
- request_module("zttranscode");
- if (zt_transcode_fops && zt_transcode_fops->open) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- if (zt_transcode_fops->owner) {
- __MOD_INC_USE_COUNT (zt_transcode_fops->owner);
-#else
- if (try_module_get(zt_transcode_fops->owner)) {
-#endif
- ret = zt_transcode_fops->open(inode, file);
- if (ret)
+ if (request_module("zttranscode")) {
+ return -ENXIO;
+ }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- __MOD_DEC_USE_COUNT (zt_transcode_fops->owner);
+ __MOD_INC_USE_COUNT (zt_transcode_fops->owner);
#else
- module_put(zt_transcode_fops->owner);
+ if (!try_module_get(zt_transcode_fops->owner)) {
+ return -ENXIO;
+ }
#endif
- }
- return ret;
+ if (zt_transcode_fops && zt_transcode_fops->open) {
+ return zt_transcode_fops->open(inode, file);
+ } else {
+ /* zttranscode module should have exported a
+ * file_operations table. */
+ WARN_ON(1);
}
return -ENXIO;
}
@@ -3124,14 +3123,11 @@ static int zt_release(struct inode *inode, struct file *file)
return zt_timer_release(inode, file);
}
if (unit == 250) {
- res = zt_transcode_fops->release(inode, file);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- if (zt_transcode_fops->owner)
- __MOD_DEC_USE_COUNT (zt_transcode_fops->owner);
-#else
- module_put(zt_transcode_fops->owner);
-#endif
- return res;
+ /* We should not be here because the zttranscode.ko module
+ * should have updated the file_operations for this file
+ * handle when the file was opened. */
+ WARN_ON(1);
+ return -EFAULT;
}
if (unit == 254) {
chan = file->private_data;
@@ -5147,8 +5143,12 @@ static int zt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
if (!unit)
return zt_ctl_ioctl(inode, file, cmd, data);
- if (unit == 250)
- return zt_transcode_fops->ioctl(inode, file, cmd, data);
+ if (unit == 250) {
+ /* zttranscode should have updated the file_operations on
+ * this file object on open, so we shouldn't be here. */
+ WARN_ON(1);
+ return -EFAULT;
+ }
if (unit == 253) {
timer = file->private_data;
diff --git a/kernel/zaptel.h b/kernel/zaptel.h
index 157747a..fd57755 100644
--- a/kernel/zaptel.h
+++ b/kernel/zaptel.h
@@ -777,8 +777,30 @@ struct zt_hwgain{
/*
* Transcoder operations
*/
+
+/* ZT_TRANSCODE_OP is an older interface that is deprecated and no longer
+ * supported.
+ */
#define ZT_TRANSCODE_OP _IOWR(ZT_CODE, 93, int)
+/* Transcoder related definitions */
+
+struct zt_transcoder_formats {
+ __u32 srcfmt;
+ __u32 dstfmt;
+};
+struct zt_transcoder_info {
+ __u32 tcnum;
+ char name[80];
+ __u32 numchannels;
+ __u32 dstfmts;
+ __u32 srcfmts;
+};
+
+#define ZT_TC_CODE 'T'
+#define ZT_TC_ALLOCATE _IOW(ZT_TC_CODE, 1, struct zt_transcoder_formats)
+#define ZT_TC_GETINFO _IOWR(ZT_TC_CODE, 2, struct zt_transcoder_info)
+
/*
* VoiceMail Waiting Indication (WMWI) -- implemented by low-level driver.
* Value: number of waiting messages (hence 0: switch messages off).
@@ -900,57 +922,6 @@ enum {
#define ZT_TONEDETECT_ON (1 << 0) /* Detect tones */
#define ZT_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */
-#define ZT_TRANSCODE_MAGIC 0x74a9c0de
-
-/* Operations */
-#define ZT_TCOP_ALLOCATE 1 /* Allocate/reset DTE channel */
-#define ZT_TCOP_TRANSCODE 2 /* Begin transcoding a block */
-#define ZT_TCOP_GETINFO 3 /* Get information (use zt_transcode_info) */
-#define ZT_TCOP_RELEASE 4 /* Release DTE channel */
-#define ZT_TCOP_TEST 5 /* test DTE device */
-typedef struct zt_transcode_info {
- unsigned int op;
- unsigned int tcnum;
- char name[80];
- int numchannels;
- unsigned int srcfmts;
- unsigned int dstfmts;
-} ZT_TRANSCODE_INFO;
-
-#define ZT_TCCONF_USETS (1 << 0) /* Use/update timestamp field */
-#define ZT_TCCONF_USESEQ (1 << 1) /* Use/update seqno field */
-
-#define ZT_TCSTAT_DSTRDY (1 << 0) /* Destination data is ready */
-#define ZT_TCSTAT_DSTBUSY (1 << 1) /* Destination data is outstanding */
-
-#define __ZT_TRANSCODE_BUFSIZ 16384
-#define ZT_TRANSCODE_HDRLEN 256
-#define ZT_TRANSCODE_BUFSIZ ((__ZT_TRANSCODE_BUFSIZ) - (ZT_TRANSCODE_HDRLEN))
-#define ZT_TRANSCODE_DSTOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
-#define ZT_TRANSCODE_SRCOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
-
-typedef struct zt_transcode_header {
- unsigned int srcfmt; /* See formats.h -- use TCOP_RESET when you change */
- unsigned int srcoffset; /* In bytes -- written by user */
- unsigned int srclen; /* In bytes -- written by user */
- unsigned int srctimestamp; /* In samples -- written by user (only used if ZT_TCCONF_USETS is set) */
- unsigned int srcseqno; /* In units -- written by user (only used if ZT_TCCONF_USESEQ is set) */
-
- unsigned int dstfmt; /* See formats.h -- use TCOP_RESET when you change */
- unsigned int dstoffset; /* In bytes -- written by user */
- unsigned int dsttimestamp; /* In samples -- read by user */
- unsigned int dstseqno; /* In units -- read by user (only used if ZT_TCCONF_USESEQ is set) */
- unsigned int dstlen; /* In bytes -- read by user */
- unsigned int dstsamples; /* In timestamp units -- read by user */
-
- unsigned int magic; /* Magic value -- ZT_TRANSCODE_MAGIC, read by user */
- unsigned int config; /* Read/write by user */
- unsigned int status; /* Read/write by user */
- unsigned char userhdr[ZT_TRANSCODE_HDRLEN - (sizeof(unsigned int) * 14)]; /* Storage for user parameters */
- unsigned char srcdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of source data */
- unsigned char dstdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of destination data */
-} ZT_TRANSCODE_HEADER;
-
struct zt_ring_cadence {
int ringcadence[ZT_MAX_CADENCE];
};
@@ -1711,27 +1682,74 @@ struct zt_transcoder_channel {
void *pvt;
struct zt_transcoder *parent;
wait_queue_head_t ready;
- int errorstatus;
- int offset;
- unsigned int chan_built;
- unsigned int built_fmts;
- unsigned int flags;
- unsigned int srcfmt;
- unsigned int dstfmt;
- struct zt_transcode_header *tch;
+ __u32 built_fmts;
+#define ZT_TC_FLAG_BUSY 1
+#define ZT_TC_FLAG_CHAN_BUILT 2
+#define ZT_TC_FLAG_NONBLOCK 3
+#define ZT_TC_FLAG_DATA_WAITING 4
+ unsigned long flags;
+ u32 dstfmt;
+ u32 srcfmt;
};
-#define ZT_TC_FLAG_BUSY (1 << 0)
-#define ZT_TC_FLAG_TRANSIENT (1 << 1)
-
+static inline int
+zt_tc_is_built(struct zt_transcoder_channel *dtc) {
+ return test_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags);
+}
+static inline void
+zt_tc_set_built(struct zt_transcoder_channel *dtc) {
+ set_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags);
+}
+static inline void
+zt_tc_clear_built(struct zt_transcoder_channel *dtc) {
+ clear_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags);
+}
+static inline int
+zt_tc_is_nonblock(struct zt_transcoder_channel *dtc) {
+ return test_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags);
+}
+static inline void
+zt_tc_set_nonblock(struct zt_transcoder_channel *dtc) {
+ set_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags);
+}
+static inline void
+zt_tc_clear_nonblock(struct zt_transcoder_channel *dtc) {
+ clear_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags);
+}
+static inline int
+zt_tc_is_data_waiting(struct zt_transcoder_channel *dtc) {
+ return test_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags);
+}
+static inline int
+zt_tc_is_busy(struct zt_transcoder_channel *dtc) {
+ return test_bit(ZT_TC_FLAG_BUSY, &dtc->flags);
+}
+static inline void
+zt_tc_set_busy(struct zt_transcoder_channel *dtc) {
+ set_bit(ZT_TC_FLAG_BUSY, &dtc->flags);
+}
+static inline void
+zt_tc_clear_busy(struct zt_transcoder_channel *dtc) {
+ clear_bit(ZT_TC_FLAG_BUSY, &dtc->flags);
+}
+static inline void
+zt_tc_set_data_waiting(struct zt_transcoder_channel *dtc) {
+ set_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags);
+}
+static inline void
+zt_tc_clear_data_waiting(struct zt_transcoder_channel *dtc) {
+ clear_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags);
+}
struct zt_transcoder {
- struct zt_transcoder *next;
+ struct list_head node;
char name[80];
int numchannels;
unsigned int srcfmts;
unsigned int dstfmts;
- int (*operation)(struct zt_transcoder_channel *channel, int op);
+ struct file_operations fops;
+ int (*allocate)(struct zt_transcoder_channel *channel);
+ int (*release)(struct zt_transcoder_channel *channel);
/* Transcoder channels */
struct zt_transcoder_channel channels[0];
};
diff --git a/kernel/zttranscode.c b/kernel/zttranscode.c
index e44895b..23a5dc8 100644
--- a/kernel/zttranscode.c
+++ b/kernel/zttranscode.c
@@ -3,7 +3,7 @@
*
* Written by Mark Spencer <markster@digium.com>
*
- * Copyright (C) 2006-2007, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -35,20 +35,11 @@
#include <linux/mm.h>
#include <linux/page-flags.h>
#include <asm/io.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
-#ifdef STANDALONE_ZAPATA
-#include "zaptel.h"
-#else
-#include <linux/zaptel.h>
-#endif
-#ifdef LINUX26
-#include <linux/moduleparam.h>
-#endif
-static int debug = 0;
-static struct zt_transcoder *trans;
+#include <zaptel.h>
+
+static int debug;
+LIST_HEAD(trans);
static spinlock_t translock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(zt_transcoder_register);
@@ -59,387 +50,375 @@ EXPORT_SYMBOL(zt_transcoder_free);
struct zt_transcoder *zt_transcoder_alloc(int numchans)
{
- struct zt_transcoder *ztc;
+ struct zt_transcoder *tc;
unsigned int x;
- size_t size = sizeof(*ztc) + (sizeof(ztc->channels[0]) * numchans);
+ size_t size = sizeof(*tc) + (sizeof(tc->channels[0]) * numchans);
- if (!(ztc = kmalloc(size, GFP_KERNEL)))
+ if (!(tc = kmalloc(size, GFP_KERNEL)))
return NULL;
- memset(ztc, 0, size);
- strcpy(ztc->name, "<unspecified>");
- ztc->numchannels = numchans;
- for (x=0;x<ztc->numchannels;x++) {
- init_waitqueue_head(&ztc->channels[x].ready);
- ztc->channels[x].parent = ztc;
- ztc->channels[x].offset = x;
- ztc->channels[x].chan_built = 0;
- ztc->channels[x].built_fmts = 0;
+ memset(tc, 0, size);
+ strcpy(tc->name, "<unspecified>");
+ tc->numchannels = numchans;
+ for (x=0;x<tc->numchannels;x++) {
+ init_waitqueue_head(&tc->channels[x].ready);
+ INIT_LIST_HEAD(&tc->node);
+ tc->channels[x].parent = tc;
}
- return ztc;
+ WARN_ON(!zt_transcode_fops);
+ /* Individual transcoders should supply their own file_operations for
+ * write and read. But they will by default use the file_operations
+ * provided by the zt_transcode layer. */
+ memcpy(&tc->fops, zt_transcode_fops, sizeof(*zt_transcode_fops));
+ return tc;
}
-static int schluffen(wait_queue_head_t *q)
+void zt_transcoder_free(struct zt_transcoder *tc)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(q, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- if (!signal_pending(current))
- schedule();
-
- current->state = TASK_RUNNING;
- remove_wait_queue(q, &wait);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- return 0;
+ kfree(tc);
}
-void zt_transcoder_free(struct zt_transcoder *ztc)
+/* Returns 1 if the item is on the list pointed to by head, otherwise, returns
+ * 0 */
+static int is_on_list(struct list_head *entry, struct list_head *head)
{
- kfree(ztc);
+ struct list_head *cur;
+ list_for_each(cur, head) {
+ if (cur == entry) return 1;
+ }
+ return 0;
}
/* Register a transcoder */
int zt_transcoder_register(struct zt_transcoder *tc)
{
- struct zt_transcoder *cur;
- int res = -EBUSY;
-
spin_lock(&translock);
- for (cur = trans; cur; cur = cur->next) {
- if (cur == tc) {
- spin_unlock(&translock);
- return res;
- }
- }
-
- tc->next = trans;
- trans = tc;
- printk("Registered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
- tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
- res = 0;
+ BUG_ON(is_on_list(&tc->node, &trans));
+ list_add_tail(&tc->node, &trans);
spin_unlock(&translock);
- return res;
+ printk(KERN_INFO "%s: Registered codec translator '%s' " \
+ "with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ THIS_MODULE->name, tc->name, tc->numchannels,
+ tc->srcfmts, tc->dstfmts);
+
+ return 0;
}
/* Unregister a transcoder */
int zt_transcoder_unregister(struct zt_transcoder *tc)
{
- struct zt_transcoder *cur, *prev;
int res = -EINVAL;
- spin_lock(&translock);
- for (cur = trans, prev = NULL; cur; prev = cur, cur = cur->next) {
- if (cur == tc)
- break;
- }
+ /* \todo Perhaps we should check to make sure there isn't a channel
+ * that is still in use? */
- if (!cur) {
+ spin_lock(&translock);
+ if (!is_on_list(&tc->node, &trans)) {
spin_unlock(&translock);
- return res;
+ printk(KERN_WARNING "%s: Failed to unregister %s, which is " \
+ "not currently registerd.\n", THIS_MODULE->name, tc->name);
+ return -EINVAL;
}
+ list_del_init(&tc->node);
+ spin_unlock(&translock);
- if (prev)
- prev->next = tc->next;
- else
- trans = tc->next;
- tc->next = NULL;
- printk("Unregistered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ printk(KERN_INFO "Unregistered codec translator '%s' with %d " \
+ "transcoders (srcs=%08x, dsts=%08x)\n",
tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
res = 0;
- spin_unlock(&translock);
return res;
}
/* Alert a transcoder */
-int zt_transcoder_alert(struct zt_transcoder_channel *ztc)
+int zt_transcoder_alert(struct zt_transcoder_channel *chan)
{
- if (debug)
- printk("ZT Transcoder Alert!\n");
- if (ztc->tch)
- ztc->tch->status &= ~ZT_TC_FLAG_BUSY;
- wake_up_interruptible(&ztc->ready);
-
+ wake_up_interruptible(&chan->ready);
return 0;
}
static int zt_tc_open(struct inode *inode, struct file *file)
{
- struct zt_transcoder_channel *ztc;
- struct zt_transcode_header *zth;
- struct page *page;
-
- if (!(ztc = kmalloc(sizeof(*ztc), GFP_KERNEL)))
- return -ENOMEM;
-
- if (!(zth = kmalloc(sizeof(*zth), GFP_KERNEL | GFP_DMA))) {
- kfree(ztc);
- return -ENOMEM;
- }
-
- memset(ztc, 0, sizeof(*ztc));
- memset(zth, 0, sizeof(*zth));
- ztc->flags = ZT_TC_FLAG_TRANSIENT | ZT_TC_FLAG_BUSY;
- ztc->tch = zth;
- if (debug)
- printk("Allocated Transcoder Channel, header is at %p!\n", zth);
- zth->magic = ZT_TRANSCODE_MAGIC;
- file->private_data = ztc;
- for (page = virt_to_page(zth);
- page < virt_to_page((unsigned long) zth + sizeof(*zth));
- page++)
- SetPageReserved(page);
-
+ const struct file_operations *original_fops;
+ BUG_ON(!zt_transcode_fops);
+ original_fops = file->f_op;
+ file->f_op = zt_transcode_fops;
+ file->private_data = NULL;
+ /* Under normal operation, this releases the reference on the Zaptel
+ * module that was created when the file was opened. zt_open is
+ * responsible for taking a reference out on this module before
+ * calling this function. */
+ module_put(original_fops->owner);
return 0;
}
-static void ztc_release(struct zt_transcoder_channel *ztc)
+static void dtc_release(struct zt_transcoder_channel *chan)
{
- struct zt_transcode_header *zth = ztc->tch;
- struct page *page;
-
- if (!ztc)
- return;
-
- ztc->flags &= ~(ZT_TC_FLAG_BUSY);
-
- if(ztc->tch) {
- for (page = virt_to_page(zth);
- page < virt_to_page((unsigned long) zth + sizeof(*zth));
- page++)
- ClearPageReserved(page);
- kfree(ztc->tch);
+ BUG_ON(!chan);
+ if (chan->parent && chan->parent->release) {
+ chan->parent->release(chan);
}
-
- ztc->tch = NULL;
- /* Actually reset the transcoder channel */
- if (ztc->flags & ZT_TC_FLAG_TRANSIENT)
- kfree(ztc);
- if (debug)
- printk("Released Transcoder!\n");
+ zt_tc_clear_busy(chan);
}
static int zt_tc_release(struct inode *inode, struct file *file)
{
- ztc_release(file->private_data);
-
+ struct zt_transcoder_channel *chan = file->private_data;
+ /* There will not be a transcoder channel associated with this file if
+ * the ALLOCATE ioctl never succeeded.
+ */
+ if (chan) {
+ dtc_release(chan);
+ }
return 0;
}
-static int do_reset(struct zt_transcoder_channel **ztc)
+/* Find a free channel on the transcoder and mark it busy. */
+static inline struct zt_transcoder_channel *
+get_free_channel(struct zt_transcoder *tc)
+
+{
+ struct zt_transcoder_channel *chan;
+ int i;
+ /* Should be called with the translock held. */
+ WARN_ON(!spin_is_locked(&translock));
+
+ for (i = 0; i < tc->numchannels; i++) {
+ chan = &tc->channels[i];
+ if (!zt_tc_is_busy(chan)) {
+ zt_tc_set_busy(chan);
+ return chan;
+ }
+ }
+ return NULL;
+}
+
+/* Search the list for a transcoder that supports the specified format, and
+ * allocate and return an available channel on it.
+ *
+ * Returns either a pointer to the allocated channel, -EBUSY if the format is
+ * supported but all the channels are busy, or -ENODEV if there are not any
+ * transcoders that support the formats.
+ */
+static struct zt_transcoder_channel *
+__find_free_channel(struct list_head *list, const struct zt_transcoder_formats *fmts)
{
- struct zt_transcoder_channel *newztc = NULL, *origztc = NULL;
- struct zt_transcode_header *zth = (*ztc)->tch;
struct zt_transcoder *tc;
- unsigned int x;
+ struct zt_transcoder_channel *chan = NULL;
unsigned int match = 0;
- if (((*ztc)->srcfmt != zth->srcfmt) ||
- ((*ztc)->dstfmt != zth->dstfmt)) {
- /* Find new transcoder */
- spin_lock(&translock);
- for (tc = trans; tc && !newztc; tc = tc->next) {
- if (!(tc->srcfmts & zth->srcfmt))
- continue;
-
- if (!(tc->dstfmts & zth->dstfmt))
- continue;
-
- match = 1;
- for (x = 0; x < tc->numchannels; x++) {
- if (tc->channels[x].flags & ZT_TC_FLAG_BUSY)
- continue;
- if ((tc->channels[x].chan_built) && ((zth->srcfmt | zth->dstfmt) != tc->channels[x].built_fmts))
- continue;
-
- newztc = &tc->channels[x];
- newztc->flags = ZT_TC_FLAG_BUSY;
- break;
+ list_for_each_entry(tc, list, node) {
+ if ((tc->dstfmts & fmts->dstfmt)) {
+ /* We found a transcoder that can handle our formats.
+ * Now look for an available channel. */
+ match = 1;
+ if ((chan = get_free_channel(tc))) {
+ /* transcoder tc has a free channel. In order
+ * to spread the load among available
+ * transcoders (when there are more than one
+ * transcoder in the system) we'll move tc
+ * to the end of the list. */
+ list_move_tail(&tc->node, list);
+ return chan;
}
}
- spin_unlock(&translock);
+ }
+ return (void*)((long)((match) ? -EBUSY : -ENODEV));
+}
- if (!newztc)
- return match ? -EBUSY : -ENOSYS;
+static long zt_tc_allocate(struct file *file, unsigned long data)
+{
+ struct zt_transcoder_channel *chan = NULL;
+ struct zt_transcoder_formats fmts;
+
+ if (copy_from_user(&fmts,
+ (struct zt_transcoder_formats*) data, sizeof(fmts))) {
+ return -EFAULT;
+ }
+
+ spin_lock(&translock);
+ chan = __find_free_channel(&trans, &fmts);
+ spin_unlock(&translock);
- /* Move transcoder header over */
- origztc = (*ztc);
- (*ztc) = newztc;
- (*ztc)->tch = origztc->tch;
- origztc->tch = NULL;
- (*ztc)->flags |= (origztc->flags & ~(ZT_TC_FLAG_TRANSIENT));
- ztc_release(origztc);
+ if (IS_ERR(chan)) {
+ return PTR_ERR(chan);
}
- /* Actually reset the transcoder channel */
- if ((*ztc)->parent && ((*ztc)->parent->operation))
- return (*ztc)->parent->operation((*ztc), ZT_TCOP_ALLOCATE);
+ /* Every transcoder channel must be associated with a parent
+ * transcoder. */
+ BUG_ON(!chan->parent);
- return -EINVAL;
-}
+ chan->srcfmt = fmts.srcfmt;
+ chan->dstfmt = fmts.dstfmt;
-static int wait_busy(struct zt_transcoder_channel *ztc)
-{
- int ret;
+ if (file->private_data) {
+ /* This open file is moving to a new channel. Cleanup and
+ * close the old channel here. */
+ dtc_release(file->private_data);
+ }
+
+ file->private_data = chan;
+ if (chan->parent->fops.owner != file->f_op->owner) {
+ if (!try_module_get(chan->parent->fops.owner)) {
+ /* Failed to get a reference on the driver for the
+ * actual transcoding hardware. */
+ return -EINVAL;
+ }
+ /* Release the reference on the existing driver. */
+ module_put(file->f_op->owner);
+ file->f_op = &chan->parent->fops;
+ }
- for (;;) {
- if (!(ztc->tch->status & ZT_TC_FLAG_BUSY))
- return 0;
- if ((ret = schluffen(&ztc->ready)))
- return ret;
+ if (file->f_flags & O_NONBLOCK) {
+ zt_tc_set_nonblock(chan);
+ } else {
+ zt_tc_clear_nonblock(chan);
}
+
+ /* Actually reset the transcoder channel */
+ if (chan->parent->allocate)
+ return chan->parent->allocate(chan);
+
+ return -EINVAL;
}
-static int zt_tc_getinfo(unsigned long data)
+static long zt_tc_getinfo(unsigned long data)
{
- struct zt_transcode_info info;
+ struct zt_transcoder_info info;
unsigned int x;
- struct zt_transcoder *tc;
+ struct zt_transcoder *cur;
+ struct zt_transcoder *tc = NULL;
- if (copy_from_user(&info, (struct zt_transcode_info *) data, sizeof(info)))
+ if (copy_from_user(&info, (const void *) data, sizeof(info))) {
return -EFAULT;
+ }
+ x = 0;
spin_lock(&translock);
- for (tc = trans, x = info.tcnum; tc && x; tc = tc->next, x--);
+ list_for_each_entry(cur, &trans, node) {
+ if (x++ == info.tcnum) {
+ tc = cur;
+ break;
+ }
+ }
spin_unlock(&translock);
- if (!tc)
+ if (!tc) {
return -ENOSYS;
+ }
zap_copy_string(info.name, tc->name, sizeof(info.name));
info.numchannels = tc->numchannels;
info.srcfmts = tc->srcfmts;
info.dstfmts = tc->dstfmts;
- return copy_to_user((struct zt_transcode_info *) data, &info, sizeof(info)) ? -EFAULT : 0;
+ return copy_to_user((void *) data, &info, sizeof(info)) ? -EFAULT : 0;
}
-static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+static ssize_t zt_tc_write(struct file *file, __user const char *usrbuf, size_t count, loff_t *ppos)
{
- int op;
- int ret;
- struct zt_transcoder_channel *ztc = file->private_data;
-
- if (cmd != ZT_TRANSCODE_OP)
+ if (file->private_data) {
+ /* file->private_data will not be NULL if ZT_TC_ALLOCATE was
+ * called, and therefore indicates that the transcoder driver
+ * did not export a read function. */
+ WARN_ON(1);
return -ENOSYS;
-
- if (get_user(op, (int *) data))
- return -EFAULT;
-
- if (debug)
- printk("ZT Transcode ioctl op = %d!\n", op);
-
- switch(op) {
- case ZT_TCOP_GETINFO:
- ret = zt_tc_getinfo(data);
- break;
- case ZT_TCOP_ALLOCATE:
- /* Reset transcoder, possibly changing who we point to */
- ret = do_reset(&ztc);
- file->private_data = ztc;
- break;
- case ZT_TCOP_RELEASE:
- ret = ztc->parent->operation(ztc, ZT_TCOP_RELEASE);
- break;
- case ZT_TCOP_TEST:
- ret = ztc->parent->operation(ztc, ZT_TCOP_TEST);
- break;
- case ZT_TCOP_TRANSCODE:
- if (!ztc->parent->operation)
- return -EINVAL;
-
- ztc->tch->status |= ZT_TC_FLAG_BUSY;
- if (!(ret = ztc->parent->operation(ztc, ZT_TCOP_TRANSCODE))) {
- /* Wait for busy to go away if we're not non-blocking */
- if (!(file->f_flags & O_NONBLOCK)) {
- if (!(ret = wait_busy(ztc)))
- ret = ztc->errorstatus;
- }
- } else
- ztc->tch->status &= ~ZT_TC_FLAG_BUSY;
- break;
- default:
- ret = -ENOSYS;
+ } else {
+ printk(KERN_INFO "%s: Attempt to write to unallocated " \
+ "channel.\n", THIS_MODULE->name);
+ return -EINVAL;
}
-
- return ret;
}
-static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma)
+static ssize_t zt_tc_read(struct file *file, __user char *usrbuf, size_t count, loff_t *ppos)
{
- struct zt_transcoder_channel *ztc = file->private_data;
- unsigned long physical;
- int res;
-
- if (!ztc)
- return -EINVAL;
-
- /* Do not allow an offset */
- if (vma->vm_pgoff) {
- if (debug)
- printk("zttranscode: Attempted to mmap with offset!\n");
+ if (file->private_data) {
+ /* file->private_data will not be NULL if ZT_TC_ALLOCATE was
+ * called, and therefore indicates that the transcoder driver
+ * did not export a write function. */
+ WARN_ON(1);
+ return -ENOSYS;
+ } else {
+ printk(KERN_INFO "%s: Attempt to read from unallocated " \
+ "channel.\n", THIS_MODULE->name);
return -EINVAL;
}
+}
- if ((vma->vm_end - vma->vm_start) != sizeof(struct zt_transcode_header)) {
- if (debug)
- printk("zttranscode: Attempted to mmap with size %d != %zd!\n", (int) (vma->vm_end - vma->vm_start), sizeof(struct zt_transcode_header));
+static long zt_tc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+{
+ switch (cmd) {
+ case ZT_TC_ALLOCATE:
+ return zt_tc_allocate(file, data);
+ case ZT_TC_GETINFO:
+ return zt_tc_getinfo(data);
+ case ZT_TRANSCODE_OP:
+ /* This is a deprecated call from the previous transcoder
+ * interface, which was all routed through the zt_ioctl in
+ * zaptel-base.c, and this ioctl request was used to indicate
+ * that the call should be forwarded to this function. Now
+ * when the file is opened, the f_ops pointer is updated to
+ * point directly to this function, and we don't need a
+ * general indication that the ioctl is destined for the
+ * transcoder.
+ *
+ * I'm keeping this ioctl here in order to explain why there
+ * might be a hole in the ioctl numbering scheme in the header
+ * files.
+ */
+ printk(KERN_WARNING "%s: ZT_TRANSCODE_OP is no longer " \
+ "supported. Please call ZT_TC ioctls directly.\n",
+ THIS_MODULE->name);
return -EINVAL;
- }
-
- physical = (unsigned long) virt_to_phys(ztc->tch);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
- res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, sizeof(struct zt_transcode_header), PAGE_SHARED);
-#else
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- res = remap_page_range(vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED);
- #else
- res = remap_page_range(vma, vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED);
- #endif
-#endif
- if (res) {
- if (debug)
- printk("zttranscode: remap failed!\n");
- return -EAGAIN;
- }
+ default:
+ return -EINVAL;
+ };
+}
- if (debug)
- printk("zttranscode: successfully mapped transcoder!\n");
+static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+ return (int)zt_tc_unlocked_ioctl(file, cmd, data);
+}
- return 0;
+static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ printk(KERN_ERR "%s: mmap interface deprecated.\n", THIS_MODULE->name);
+ return -ENOSYS;
}
static unsigned int zt_tc_poll(struct file *file, struct poll_table_struct *wait_table)
{
- struct zt_transcoder_channel *ztc = file->private_data;
+ int ret;
+ struct zt_transcoder_channel *chan = file->private_data;
- if (!ztc)
+ if (!chan) {
+ /* This is because the ZT_TC_ALLOCATE ioctl was not called
+ * before calling poll, which is invalid. */
return -EINVAL;
+ }
- poll_wait(file, &ztc->ready, wait_table);
- return ztc->tch->status & ZT_TC_FLAG_BUSY ? 0 : POLLPRI;
+ poll_wait(file, &chan->ready, wait_table);
+
+ ret = zt_tc_is_busy(chan) ? 0 : POLLPRI;
+ ret |= zt_tc_is_built(chan) ? POLLOUT : 0;
+ ret |= zt_tc_is_data_waiting(chan) ? POLLIN : 0;
+ return ret;
}
static struct file_operations __zt_transcode_fops = {
- owner: THIS_MODULE,
- llseek: NULL,
- open: zt_tc_open,
+ owner: THIS_MODULE,
+ open: zt_tc_open,
release: zt_tc_release,
- ioctl: zt_tc_ioctl,
- read: NULL,
- write: NULL,
- poll: zt_tc_poll,
- mmap: zt_tc_mmap,
- flush: NULL,
- fsync: NULL,
- fasync: NULL,
+ ioctl: zt_tc_ioctl,
+ read: zt_tc_read,
+ write: zt_tc_write,
+ poll: zt_tc_poll,
+ mmap: zt_tc_mmap,
+#if HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: zt_tc_unlocked_ioctl,
+#endif
};
static struct zt_chardev transcode_chardev = {
@@ -447,12 +426,12 @@ static struct zt_chardev transcode_chardev = {
.minor = 250,
};
-int zttranscode_init(void)
+int zt_transcode_init(void)
{
int res;
if (zt_transcode_fops) {
- printk("Whoa, zt_transcode_fops already set?!\n");
+ printk(KERN_WARNING "zt_transcode_fops already set.\n");
return -EBUSY;
}
@@ -461,30 +440,25 @@ int zttranscode_init(void)
if ((res = zt_register_chardev(&transcode_chardev)))
return res;
- printk("Zaptel Transcoder support loaded\n");
-
+ printk(KERN_INFO "%s: Loaded.\n", THIS_MODULE->name);
return 0;
}
-void zttranscode_cleanup(void)
+void zt_transcode_cleanup(void)
{
zt_unregister_chardev(&transcode_chardev);
zt_transcode_fops = NULL;
- printk("Zaptel Transcoder support unloaded\n");
+ printk(KERN_DEBUG "%s: Unloaded.\n", THIS_MODULE->name);
}
-#ifdef LINUX26
module_param(debug, int, S_IRUGO | S_IWUSR);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_DESCRIPTION("Zaptel Transcoder Support");
MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
-module_init(zttranscode_init);
-module_exit(zttranscode_cleanup);
+module_init(zt_transcode_init);
+module_exit(zt_transcode_cleanup);