[zaptel-commits] sruffell: branch sruffell/zaptel-1.4-transcoder r4200 - in /team/sruffell/zap...
SVN commits to the Zaptel project
zaptel-commits at lists.digium.com
Mon Apr 28 03:31:21 CDT 2008
Author: sruffell
Date: Mon Apr 28 03:31:19 2008
New Revision: 4200
URL: http://svn.digium.com/view/zaptel?view=rev&rev=4200
Log:
Saving some initial work at some experiments on a read / write interface for
the zaptel transcoder.
Added:
team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/codec_test.h
- copied, made public unchanged from r4199, team/sruffell/private/transcoder/kernel/wctc4xxp/codec_test.h
team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/codec_test_threaded.c
- copied, made public, changed from r4199, team/sruffell/private/transcoder/kernel/wctc4xxp/codec_test_threaded.c
Modified:
team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/Makefile
team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/base.c
team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/codec_test.c
team/sruffell/zaptel-1.4-transcoder/kernel/zaptel-base.c
team/sruffell/zaptel-1.4-transcoder/kernel/zaptel.h
team/sruffell/zaptel-1.4-transcoder/kernel/zttranscode.c
Modified: team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/Makefile
URL: http://svn.digium.com/view/zaptel/team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/Makefile?view=diff&rev=4200&r1=4199&r2=4200
==============================================================================
--- team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/Makefile (original)
+++ team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/Makefile Mon Apr 28 03:31:19 2008
@@ -8,8 +8,14 @@
tests: codec_test
+CFLAGS += -I../ -DSTANDALONE_ZAPATA
+
codec_test: codec_test.c ../zaptel.h
- $(CC) -o $@ $< $(CFLAGS)
+ $(CC) -g -o $@ $< $(CFLAGS)
+
+codec_test_threaded: codec_test_threaded.c ../zaptel.h
+ $(CC) -o $@ $< $(CFLAGS) -lpthread
+
clean:
rm -rf codec_test
Modified: team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/base.c
URL: http://svn.digium.com/view/zaptel/team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/base.c?view=diff&rev=4200&r1=4199&r2=4200
==============================================================================
--- team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/base.c (original)
+++ team/sruffell/zaptel-1.4-transcoder/kernel/wctc4xxp/base.c Mon Apr 28 03:31:19 2008
@@ -1,9 +1,10 @@
/*
* Wildcard TC400B Driver
*
- * Written by John Sloan <jsloan at digium.com>
+ * Written by John Sloan <jsloan at digium.com> and
+ * Shaun Ruffell <sruffell at digium.com>
*
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -21,8 +22,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * Glossary:
+ *
+ * DTE - Digium Transcoding Engine
+ *
*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -34,8 +38,6 @@
#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>
@@ -43,10 +45,37 @@
#include <linux/workqueue.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
+#include <linux/if_ether.h>
+#include <linux/timer.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
#endif
+
#include "zaptel.h"
+
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET 2
+#ifndef DEFERRED_PROCESSING
+# define DEFERRED_PROCESSING INTERRUPT
+#endif
+
+#define WARN() WARN_ON(1)
+#define DTE_PRINTK(_wc, _lvl, _fmt, _args...) \
+ printk(KERN_##_lvl "%s: " _fmt, (_wc)->board_name, ## _args)
+
+#define DTE_DEBUG_GENERAL (1 << 0)
+#define DTE_DEBUG_CHANNEL_SETUP (1 << 1)
+#define DTE_DEBUG_RTP_TX (1 << 2)
+#define DTE_DEBUG_RTP_RX (1 << 3)
+
+#define DTE_DEBUG(_wc, _dbgmask, _fmt, _args...) \
+ if ((debug & _dbgmask) == (_dbgmask)) { \
+ printk(KERN_DEBUG "%s: " _fmt, (_wc)->board_name, ## _args);\
+ } \
+
+#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 USE_TEST_HW */
#define USE_TDM_CONFIG
@@ -57,8 +86,15 @@
#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
+#if 0
+#define HERE() printk(KERN_DEBUG "HERE: %s:%d\n", __FILE__, __LINE__);
+#define ENTERING() printk(KERN_DEBUG "Entering %s \n", __FUNCTION__);
+#define LEAVING() printk(KERN_DEBUG "Leaving %s (%d)\n", __FUNCTION__, __LINE__);
+#else
+#define HERE() do {;} while (0)
+#define ENTERING() do {;} while (0)
+#define LEAVING() do {;} while (0)
+#endif
#define DTE_FORMAT_ULAW 0x00
#define DTE_FORMAT_G723_1 0x04
@@ -77,25 +113,9 @@
#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 */
-
-#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
-
-#define SFRAME_SIZE MAX_COMMAND_LEN
-
-#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+#define SFRAME_SIZE 1518
#define MDIO_SHIFT_CLK 0x10000
-#define MDIO_DATA_WRITE0 0x00000
#define MDIO_DATA_WRITE1 0x20000
#define MDIO_ENB 0x00000
#define MDIO_ENB_IN 0x40000
@@ -106,6 +126,8 @@
#define RCV_CSMENCAPS_ACK 3
#define RCV_OTHER 99
+/* \todo It might be clearer if these commands were mapped to packed stuctures
+ * instead of used as byte arrays. */
/* TDM Commands */
#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30
@@ -189,6 +211,7 @@
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 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, \
@@ -271,70 +294,235 @@
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 {
+#define ETH_P_CSM_ENCAPS 0x889B
+/* Ehernet packet type for communication control information to the DTE. */
+struct csm_encaps_hdr {
+ /* CSM_ENCAPS HEADER */
+ __be16 op_code;
+ __u8 seq_num;
+ __u8 control;
+ __be16 channel;
+ /* COMMON PART OF PAYLOAD HEADER */
+ __u8 length;
+ __u8 index;
+ __u8 class;
+ __u8 type;
+ __be16 function;
+ __be16 reserved;
+ __le16 params[0]; /* Must be last (AND SWITCHES TO LITTLE ENDIAN) */
+} __attribute__((packed));
+
+
+struct dte_cmd {
+ u8 cmd[SFRAME_SIZE];
+ unsigned int debug;
unsigned int cmdlen;
- unsigned char cmd[MAX_COMMAND_LEN];
+ struct list_head node;
+/*! If set, this command will be freed automatically after completing
+ * transmission.
+ */
+#define NO_AUTO_FREE_CMD (1 << 0)
+#define TX_COMPLETE (1 << 1)
+ unsigned long flags;
+ struct completion complete;
};
+/*! In-memory structure shared by the host and the adapter. */
+struct dte_descriptor {
+ u32 des0;
+ u32 des1;
+ u32 buffer1;
+ u32 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 dte_descriptor_ring {
+ /* Pointer to an array of descriptors to give to hardware. */
+ struct dte_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 dte_cmd *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;
+};
+
+/* Returns the desriptor at index.
+ *
+ * We need this function because we do not know what the padding on the
+ * descriptors will be.
+ */
+static inline struct dte_descriptor *
+dte_descriptor(struct dte_descriptor_ring *dr, int index)
+{
+ struct dte_descriptor *d;
+ d = (struct dte_descriptor *)((u8*)dr->desc +
+ ((sizeof(*d) + dr->padding) * index));
+ return d;
+}
+
+static int
+dte_initialize_descriptor_ring(struct pci_dev *pdev, struct dte_descriptor_ring *dr,
+ u32 des1, unsigned int direction)
+{
+ int i;
+ const u32 END_OF_RING = 0x02000000;
+ u8 cache_line_size = 0;
+ struct dte_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))
+ {
+ dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d);
+ }
+
+ dr->desc = pci_alloc_consistent(pdev,
+ (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma);
+
+ if (!dr->desc) {
+ return -ENOMEM;
+ }
+
+ memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = dte_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;
+}
+
+#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)
+
+/*! Submit a command to the descriptor list for processing by the DTE. */
+static int
+dte_submit(struct dte_descriptor_ring* dr, struct dte_cmd *c)
+{
+ volatile struct dte_descriptor *d;
+ unsigned int tail = dr->tail;
+ unsigned long flags;
+ unsigned int len;
+ const unsigned int BUFFER1_SIZE_MASK = 0x7ff;
+
+ WARN_ON(!c);
+ WARN_ON(c->cmdlen > SFRAME_SIZE);
+ len = (c->cmdlen < MIN_PACKET_LEN) ? MIN_PACKET_LEN : c->cmdlen;
+ if (c->cmdlen > SFRAME_SIZE) {
+ printk(KERN_ERR "Invalid frame size: %d.\n", c->cmdlen);
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&dr->lock, flags);
+
+ d = dte_descriptor(dr, tail);
+ if (d->buffer1) {
+ spin_unlock_irqrestore(&dr->lock, flags);
+ /* 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 = dma_map_single(&dr->pdev->dev, c->cmd,
+ SFRAME_SIZE, dr->direction);
+
+ SET_OWNED(d); /* That's it until the hardware is done with it. */
+
+ dr->pending[tail] = c;
+ dr->tail = (++tail) & DRING_MASK;
+ ++dr->count;
+
+ spin_unlock_irqrestore(&dr->lock, flags);
+
+ return 0;
+}
+
+static inline struct dte_cmd*
+dte_retrieve(struct dte_descriptor_ring *dr)
+{
+ volatile struct dte_descriptor *d;
+ struct dte_cmd *c;
+ unsigned long flags;
+ unsigned int head = dr->head;
+ spin_lock_irqsave(&dr->lock, flags);
+ d = dte_descriptor(dr, head);
+ if (d->buffer1 && !OWNED(d)) {
+ dma_unmap_single(&dr->pdev->dev, 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);
+ } else {
+ c = NULL;
+ }
+ spin_unlock_irqrestore(&dr->lock, flags);
+ return c;
+}
+
+#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
+
struct wcdte {
- struct pci_dev *dev;
- char *variety;
- unsigned int intcount;
- unsigned int rxints;
- unsigned int txints;
+ char board_name[40];
+ struct pci_dev *pdev;
+ const char *variety;
unsigned int intmask;
int pos;
- int freeregion;
- int rdbl;
- int tdbl;
int cards;
spinlock_t reglock;
wait_queue_head_t regq;
int rcvflags;
struct semaphore chansem;
- struct semaphore cmdqsem;
- struct cmdq cmdq[MAX_COMMANDS];
- unsigned int cmdq_wndx;
- unsigned int cmdq_rndx;
+ spinlock_t cmd_list_lock;
+ struct list_head cmd_list;
+ /* This is a list to hold those commands which were flagged to not
+ * auto delete, but which we stopped waiting for because of a signal.
+ * Use the cmd_list_lock to protect this list. */
+ struct list_head lost_cmd_list;
unsigned int last_seqno;
unsigned int last_rseqno;
@@ -342,56 +530,236 @@
unsigned int last_rcommand;
unsigned int last_rparm1;
unsigned int seq_num;
- long timeout;
-
- unsigned int dsp_crashed;
- unsigned int dumping;
-
- unsigned int ztsnd_rtx;
- unsigned int ztsnd_0010_rtx;
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 */
- int wqueints;
+#if DEFERRED_PROCESSING == WORKQUEUE
struct workqueue_struct *dte_wq;
struct work_struct dte_work;
+#endif
+
+ struct dte_descriptor_ring txd;
+ struct dte_descriptor_ring rxd;
struct zt_transcoder *uencode;
struct zt_transcoder *udecode;
+ struct channel_pvt *encoders;
+ struct channel_pvt *decoders;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_file;
+#endif
+ /* In order to add this to the list of cards checked by the watchdog
+ * timer. */
+ struct list_head watchdog_node;
};
+static inline void __wcdte_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)
+{
+ return inl(wc->iobase + addr);
+}
+
+static inline void wcdte_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);
+}
+
+/* Instruct the DTE to read in the next rx descriptor */
+static inline void dte_receive_demand_poll(struct wcdte *wc)
+{
+ wcdte_setctl(wc, 0x0010, 0x00000000);
+}
+
+/* Instruct the DTE to read in the next tx descriptor */
+static inline void dte_transmit_demand_poll(struct wcdte *wc)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __wcdte_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.
+ */
+ __wcdte_setctl(wc, 0x0008, 0x00000000);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline struct dte_cmd *
+__alloc_cmd(gfp_t alloc_flags, unsigned long cmd_flags)
+{
+ struct dte_cmd *cmd;
+
+ cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
+ if (likely(cmd)) {
+ memset(cmd, 0, sizeof(*cmd));
+ INIT_LIST_HEAD(&cmd->node);
+ cmd->debug = 0xdeadbeef;
+ init_completion(&cmd->complete);
+ cmd->flags = cmd_flags;
+ }
+ return cmd;
+}
+static inline struct dte_cmd *
+alloc_cmd(void)
+{
+ return __alloc_cmd(GFP_KERNEL, 0);
+}
+
+static inline void
+free_cmd(struct dte_cmd *cmd)
+{
+ WARN_ON(0xdeadbeef != cmd->debug);
+ kmem_cache_free(cmd_cache, cmd);
+ return;
+}
+
+static void
+wcdte_cleanup_descriptor_ring(struct dte_descriptor_ring *dr)
+{
+ int i;
+ struct dte_descriptor *d;
+ unsigned long flags;
+
+ /* NOTE: The DTE must be in the stopped state. */
+
+ spin_lock_irqsave(&dr->lock, flags);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = dte_descriptor(dr, i);
+ if (d->buffer1) {
+ dma_unmap_single(&dr->pdev->dev, d->buffer1,
+ SFRAME_SIZE, dr->direction);
+ d->buffer1 = 0;
+ free_cmd(dr->pending[i]);
+ dr->pending[i] = NULL;
+ }
+ }
+ dr->head = 0;
+ dr->tail = 0;
+ dr->count = 0;
+ spin_unlock_irqrestore(&dr->lock, flags);
+ pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE, dr->desc, dr->desc_dma);
+}
+
+static void
+wcdte_cleanup_command_list(struct wcdte *wc)
+{
+ unsigned long flags;
+ struct dte_cmd *cmd;
+ struct dte_cmd *temp;
+
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_for_each_entry_safe(cmd, temp, &wc->cmd_list, node) {
+ list_del(&cmd->node);
+ free_cmd(cmd);
+ }
+ list_for_each_entry_safe(cmd, temp, &wc->lost_cmd_list, node) {
+ list_del(&cmd->node);
+ free_cmd(cmd);
+ }
+ WARN_ON(!list_empty(&wc->cmd_list));
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+}
+
+static void wcdte_cleanup_lost_command_list(struct wcdte *wc)
+{
+ unsigned long flags;
+ struct dte_cmd *cmd;
+ struct dte_cmd *temp;
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_for_each_entry_safe(cmd, temp, &wc->lost_cmd_list, node) {
+ if (cmd->flags & TX_COMPLETE) {
+ list_del(&cmd->node);
+ free_cmd(cmd);
+ }
+ }
+ WARN_ON(!list_empty(&wc->cmd_list));
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+}
+
+/**
+ * The command list is used to store commands that couldn't fit in the tx
+ * descriptor list when they were requested.
+ */
+static void
+dte_add_to_command_list(struct wcdte *wc, struct dte_cmd *cmd)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_add_tail(&cmd->node, &wc->cmd_list);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+}
+
+static void
+dte_transmit_cmd(struct wcdte *wc, struct dte_cmd *cmd)
+{
+ int res;
+
+ if (cmd->cmdlen < MIN_PACKET_LEN) {
+ memset(&cmd->cmd[cmd->cmdlen],0,MIN_PACKET_LEN-cmd->cmdlen);
+ }
+ if (unlikely((res=dte_submit(&wc->txd, cmd)))) {
+ if (-EBUSY == res) {
+ dte_add_to_command_list(wc, cmd);
+ } else {
+ /* Unknown return value... */
+ WARN_ON(1);
+ }
+ } else {
+ dte_transmit_demand_poll(wc);
+ }
+}
+
struct wcdte_desc {
- char *name;
+ const char *short_name;
+ const char *long_name;
int flags;
};
-static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 };
-static struct wcdte_desc wctce400 = { "Wildcard TCE400+TC400M", 0 };
+static struct wcdte_desc wctc400p = {
+ .short_name = "tc400b",
+ .long_name = "Wildcard TC400P+TC400M",
+ .flags = 0,
+};
+
+static struct wcdte_desc wctce400 = {
+ .short_name = "tce400",
+ .long_name = "Wildcard TCE400+TC400M",
+ .flags = 0,
+};
static struct wcdte *ifaces[WC_MAX_IFACES];
-
+typedef enum { DECODER=0, ENCODER, } encode_t;
+
+struct channel_stats {
+ atomic_t packets_sent;
+ atomic_t packets_received;
+};
/*
* 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
+ * CCITT Recommendation G.721. The field names are essentially identical
* to variable names in the bit level description of the coding algorithm
* included in this Recommendation.
*/
-struct dte_state {
- int encoder; /* If we're an encoder */
+struct channel_pvt {
+ spinlock_t lock; /* Lock for this structure */
+ encode_t encoder; /* If we're an encoder */
struct wcdte *wc;
unsigned int timestamp;
@@ -399,148 +767,128 @@
unsigned int cmd_seqno;
- 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 */
-
- 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 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 */
- unsigned int packets_sent;
- unsigned int packets_received;
+ struct channel_stats stats;
unsigned int last_dte_seqno;
unsigned int dte_seqno_rcv;
unsigned char ssrc;
+ struct list_head rx_queue; /* Transcoded packets for this channel. */
+ wait_queue_head_t waitq;
};
-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;
-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);
+/* Forward Declarations \todo Review: are these are really necessary? */
+static int wcdte_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, u8 simple, u8 complicated);
+static int wcdte_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt);
static int __wcdte_setup_channels(struct wcdte *wc);
-
-static int __dump_descriptors(struct wcdte *wc)
-{
- volatile unsigned char *writechunk, *readchunk;
- int o2, i, j;
-
- if (debug_des_cnt == 0)
- return 1;
-
- 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--;
- return 0;
-}
-
-/* Sanity check values */
-static inline int zt_tc_sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
-{
- 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;
-}
-
-static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc)
-{
- state_ptr->encoder = encoder;
- state_ptr->wc = wc;
- state_ptr->timestamp = 0;
- state_ptr->seqno = 0;
-
- 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;
-
- state_ptr->chan_in_num = 999;
- state_ptr->chan_out_num = 999;
-
- state_ptr->ssrc = 0x78;
+static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, unsigned int wait_mode);
+
+ /* \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 zt_send_cmd(wc, command) ({ \
+ int __res; \
+ u8 _cmd[] = command; \
+ struct dte_cmd *cmd; \
+ if (!(cmd=__alloc_cmd(GFP_KERNEL, NO_AUTO_FREE_CMD))) \
+ return -ENOMEM; \
+ BUG_ON(sizeof(_cmd) > SFRAME_SIZE); \
+ memcpy(cmd->cmd, _cmd, sizeof(_cmd)); \
+ cmd->cmdlen = sizeof(_cmd); \
+ __res = __zt_send_cmd(wc, cmd); \
+ __res; \
+})
+
+static int __zt_send_cmd(struct wcdte *wc, struct dte_cmd *cmd)
+{
+ int ret = 0;
+ u16 command;
+ unsigned int retries = 0;
+ const unsigned int MAX_RETRIES = 1;
+
+ command = (cmd->cmd[0x18] << 8) | cmd->cmd[0x19];
+
+ wc->last_command_sent = command;
+ wc->last_seqno = cmd->cmd[16];
+
+ /* \todo I put the retry code in here, before determining that packets
+ * were sitting in the tx queue. I haven't yet seen a case where the
+ * retry actually allows a packet to complete. Might be a candidate
+ * for removal in order to simplify this function. */
+ while (retries++ < MAX_RETRIES) {
+ dte_transmit_cmd(wc, cmd);
+#if 0 /* This is debug code when investigating the source of the timeouts... */
+ if (wait_for_completion_killable(&cmd->complete)) {
+ DTE_DEBUG(wc, DTE_DEBUG_GENERAL,
+ "Failed to complete transmit.\n");
+
+ /* Save this command on the lost list in order to be
+ * cleaned up later. */
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_add_tail(&cmd->node, &wc->lost_cmd_list);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+ return -EINTR;
+ }
+#else
+ wait_for_completion(&cmd->complete);
+#endif
+ /* \todo why is this command treated differently? */
+ if (0x0000 == command) {
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2);
+ } else {
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0);
+ }
+ if (unlikely(-EIO == ret)) {
+ continue;
+ }
+ break;
+ }
+ free_cmd(cmd);
+
+
+ return ret;
+}
+
+static void dte_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;
+
+ cpvt->ssrc = 0x78;
- if (encoder == 1)
- {
- state_ptr->timeslot_in_num = channel * 2;
- state_ptr->timeslot_out_num = channel * 2 + 1;
+ if (ENCODER == encoder) {
+ cpvt->timeslot_in_num = channel * 2;
+ cpvt->timeslot_out_num = channel * 2 + 1;
} else {
- state_ptr->timeslot_in_num = channel * 2 + 1;
- state_ptr->timeslot_out_num = channel * 2;
- }
-}
-
-static unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt)
-{
- unsigned int pt;
+ cpvt->timeslot_in_num = channel * 2 + 1;
+ cpvt->timeslot_out_num = channel * 2;
+ }
+ spin_lock_init(&cpvt->lock);
+ INIT_LIST_HEAD(&cpvt->rx_queue);
+ init_waitqueue_head(&cpvt->waitq);
+}
+
+static inline u8 wcdte_zapfmt_to_dtefmt(unsigned int fmt)
+{
+ u8 pt;
- switch(fmt)
- {
+ switch(fmt) {
case ZT_FORMAT_G723_1:
pt = DTE_FORMAT_G723_1;
break;
@@ -555,39 +903,10 @@
break;
default:
pt = DTE_FORMAT_UNDEF;
- }
-
- return(pt);
-}
-
-static inline void __wcdte_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)
-{
- return inl(wc->iobase + addr);
-}
-
-static inline void wcdte_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);
-}
-
-static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s)
-{
- int o2 = 0;
- o2 += dbl * 4;
-
- if (!tx)
- o2 += ERING_SIZE * 4;
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
-
- wcdte_setctl(wc, 0x0008, 0x00000000);
+ break;
+ }
+
+ return pt;
}
static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr)
@@ -600,567 +919,605 @@
return val;
}
-static inline int __transmit_demand(struct wcdte *wc)
-{
- volatile unsigned char *writechunk;
- int o2,i,j;
- unsigned int reg, xmt_length;
-
- reg = wcdte_getctl(wc, 0x0028) & 0x00700000;
+/* \todo This function is a candidate for refactorization, but I want to make
+ * sure the interface is stable before doing so. */
+static void
+init_CMD_MSG_IP_UDP_RTP(const struct zt_transcoder_channel *ztc,
+ unsigned int inbytes, const struct channel_pvt *cpvt, struct dte_cmd *cmd)
+{
+ unsigned int ipchksum;
+ u8 msg[] = CMD_MSG_IP_UDP_RTP(
+ ((inbytes+40) >> 8) & 0xFF,
+ (inbytes+40) & 0xFF,
+ cpvt->seqno & 0xFF,
+ 0x00,
+ 0x00,
+ (((cpvt->timeslot_out_num) >> 8)+0x50) & 0xFF,
+ (cpvt->timeslot_out_num) & 0xFF,
+ (((cpvt->timeslot_in_num) >> 8)+0x50) & 0xFF,
+ (cpvt->timeslot_in_num) & 0xFF,
+ ((inbytes+20) >> 8) & 0xFF,
+ (inbytes+20) & 0xFF,
+ 0x00,
+ 0x00,
+ wcdte_zapfmt_to_dtefmt(ztc->srcfmt),
+ ((cpvt->seqno) >> 8) & 0xFF,
+ (cpvt->seqno) & 0xFF,
+ ((cpvt->timestamp) >> 24) & 0xFF,
+ ((cpvt->timestamp) >> 16) & 0xFF,
+ ((cpvt->timestamp) >> 8) & 0xFF,
+ (cpvt->timestamp) & 0xFF,
+ (cpvt->ssrc) & 0xFF);
+ BUG_ON(sizeof(msg) > SFRAME_SIZE);
+ memcpy(&cmd->cmd[0], &msg[0], sizeof(msg));
+ cmd->cmdlen = sizeof(msg);
+
+ ipchksum = 0x9869 + (cmd->cmd[16] << 8) + cmd->cmd[17]
+ + (cmd->cmd[18] << 8) + cmd->cmd[19];
+
+ while (ipchksum >> 16) {
+ ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16);
+ }
+
+ ipchksum = (~ipchksum) & 0xFFFF;
+
+ cmd->cmd[24] = ipchksum >> 8;
+ cmd->cmd[25] = ipchksum & 0xFF;
+
+ return;
+}
+
+static void
+wcdte_cleanup_channel_private(struct wcdte *wc, struct channel_pvt *cpvt)
+{
+ unsigned long flags;
+ struct dte_cmd *cmd, *temp;
+
+ spin_lock_irqsave(&cpvt->lock, flags);
+ list_for_each_entry_safe(cmd, temp, &cpvt->rx_queue, node) {
+ list_del(&cmd->node);
+ free_cmd(cmd);
+ }
+ spin_unlock_irqrestore(&cpvt->lock, flags);
+}
+
+static int
+wcdte_mark_channel_complement_built(struct wcdte *wc, struct zt_transcoder_channel *ztc)
+{
+ int index;
+ struct channel_pvt *cpvt = ztc->pvt;
+ struct zt_transcoder_channel *compl_ztc;
+ struct channel_pvt *compl_cpvt;
+
+ BUG_ON(!cpvt);
+ index = cpvt->timeslot_in_num/2;
+ BUG_ON(index >= wc->numchannels);
+ if (cpvt->encoder == 1) {
+ compl_ztc = &(wc->udecode->channels[index]);
+ } else {
+ compl_ztc = &(wc->uencode->channels[index]);
+ }
+ WARN_ON(compl_ztc->chan_built); /* It shouldn't already have been built... */
+ compl_ztc->chan_built = 1;
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "Marking (%08x)->chan_built = %d\n", (u32)compl_ztc, compl_ztc->chan_built);
+ compl_ztc->built_fmts = ztc->dstfmt | ztc->srcfmt;
+ compl_cpvt = compl_ztc->pvt;
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "ztc: %08x is the complement to %08x\n", (u32)compl_ztc, (u32)ztc);
+ compl_cpvt->chan_in_num = cpvt->chan_out_num;
+ compl_cpvt->chan_out_num = cpvt->chan_in_num;
+ wcdte_cleanup_channel_private(wc, compl_cpvt);
+
+ return 0;
+}
+
+static int
+dte_operation_allocate(struct zt_transcoder_channel *ztc)
+{
+ int res;
+ u8 dte_srcfmt; /* Digium Transcoder Engine Source Format */
+ u8 dte_dstfmt; /* Digium Transcoder Engine Dest Format */
+ struct channel_pvt *cpvt = ztc->pvt;
+ struct wcdte *wc = cpvt->wc;
+
+ ENTERING();
+
+ BUG_ON(!cpvt);
+ BUG_ON(!wc);
+
+
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "Entering %s for channel %08x.\n", __FUNCTION__, (u32)ztc);
+ if (down_interruptible(&wc->chansem)) {
+ HERE();
+ return -EINTR;
+ }
+
+ /* If the channel is already built then we're done. */
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "(%08x)->chan_built = %d\n", (u32)ztc, ztc->chan_built);
+ if (ztc->chan_built) {
+ up(&wc->chansem);
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "Allocating channel %08x which is already built.\n", (u32)ztc);
+ LEAVING();
+ return 0;
+ }
+
+ /* Anything on the rx queue now is old news... */
+ wcdte_cleanup_channel_private(wc, cpvt);
+
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "Allocating a new channel: %08x.\n", (u32)ztc);
+
+ dte_srcfmt = wcdte_zapfmt_to_dtefmt(ztc->srcfmt);
+ dte_dstfmt = wcdte_zapfmt_to_dtefmt(ztc->dstfmt);
+ if ((res = wcdte_create_channel_pair(wc, cpvt, dte_srcfmt, dte_dstfmt))) {
+ /* There was a problem creating the channel.... */
+ up(&wc->chansem);
+ LEAVING();
+ return res;
+ }
+
+ /* Mark this channel as built */
+ ztc->chan_built = 1;
+ ztc->built_fmts = ztc->dstfmt | ztc->srcfmt;
+
+ /* Mark the channel complement (other half of encoder/decoder pair) as built */
+ res = wcdte_mark_channel_complement_built(wc, ztc);
+
+ up(&wc->chansem);
+ LEAVING();
+ return res;
+}
+
+static int
+dte_operation_release(struct zt_transcoder_channel *ztc)
+{
+ int res;
+ int index;
+ /* This is the 'complimentary channel' to ztc. I.e., if ztc is an
+ * encoder, compl_ztc is the decoder and vice-versa */
+ struct zt_transcoder_channel *compl_ztc;
+ struct channel_pvt *compl_cpvt;
+ struct channel_pvt *cpvt = ztc->pvt;
+ struct wcdte *wc = cpvt->wc;
+
+ ENTERING();
+ BUG_ON(!cpvt);
+ BUG_ON(!wc);
+
+ wcdte_cleanup_lost_command_list(wc);
+
+ /* The release operation must succeed, we can't abort it in light of a
+ * signal.
+ */
+ down(&wc->chansem);
+
+ /* Remove any packets that are waiting on the outbound queue. */
+ wcdte_cleanup_channel_private(wc, cpvt);
- /* Already transmiting, no need to demand another */
- if (!((reg == 0) || (reg = 6)))
- return(1);
-
- /* Nothing to transmit */
- if (wc->cmdq_rndx == wc->cmdq_wndx)
- return(1);
-
- /* Nothing to transmit */
- if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 )
- return(1);
-
- writechunk = (volatile unsigned char *)(wc->writechunk);
-
- writechunk += wc->tdbl * SFRAME_SIZE;
-
- o2 = wc->tdbl * 4;
-
- do
- {
- } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000));
-
- xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen;
- if (xmt_length < 64)
- xmt_length = 64;
+ index = cpvt->timeslot_in_num/2;
+ BUG_ON(index >= wc->numchannels);
+
+ if (ENCODER == cpvt->encoder) {
+ compl_ztc = &(wc->udecode->channels[index]);
+ } else {
+ compl_ztc = &(wc->uencode->channels[index]);
+ }
+
+ BUG_ON(!compl_ztc);
+
+ /* If the channel complement (other half of the encoder/decoder pair) is being used... */
+ if ((compl_ztc->flags & ZT_TC_FLAG_BUSY)) {
+ up(&wc->chansem);
+ LEAVING();
+ return -EBUSY;
+ }
+
+ if ((res = wcdte_destroy_channel_pair(wc, cpvt))) {
+ /* There was a problem destorying the channels.*/
+ /* \todo log a message */
+ up(&wc->chansem);
+ HERE();
+ LEAVING();
+ return res;
+ }
+
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %08x\n", (u32)ztc);
+ /* Mark this channel as not built */
+ ztc->chan_built = 0;
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "(%08x)->chan_built = %d\n", (u32)ztc, ztc->chan_built);
+ ztc->built_fmts = 0;
+ cpvt->chan_in_num = INVALID;
+ cpvt->chan_out_num = INVALID;
- 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");
- }
-
- wc->cmdq[wc->cmdq_rndx].cmdlen = 0;
-
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
- wcdte_setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */
+ /* Mark the channel complement as not built */
+ compl_ztc->chan_built = 0;
+ DTE_DEBUG(wc, DTE_DEBUG_CHANNEL_SETUP, "(%08x)->chan_built = %d\n", (u32)compl_ztc, compl_ztc->chan_built);
+ compl_ztc->built_fmts = 0;
+ compl_cpvt = compl_ztc->pvt;
+ compl_cpvt->chan_in_num = INVALID;
+ compl_cpvt->chan_out_num = INVALID;
+
+ cpvt->dte_seqno_rcv = 0;
+
+ up(&wc->chansem);
+ LEAVING();
+ return res;
+}
+
+static inline struct dte_cmd*
+get_ready_cmd(struct channel_pvt *cpvt)
+{
+ struct dte_cmd *cmd;
+ unsigned long flags;
+ spin_lock_irqsave(&cpvt->lock, flags);
+ if (!list_empty(&cpvt->rx_queue)) {
+ cmd = list_entry(cpvt->rx_queue.next, struct dte_cmd, node);
+ list_del_init(&cmd->node);
+ } else {
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&cpvt->lock, flags);
+ return cmd;
+}
+
+/* Called with a buffer in which to copy a transcoded frame. */
+static ssize_t
+dte_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ struct zt_transcoder_channel *ztc = file->private_data;
+ struct channel_pvt *cpvt = ztc->pvt;
+ struct wcdte *wc = cpvt->wc;
+ struct dte_cmd *cmd;
+ u8 rcodec;
+ u16 rchannel;
+ u16 rlen;
+ u16 rtp_rseq;
+ u16 rtp_eseq;
+ const u8 *packet;
+
+ BUG_ON(!ztc);
+ BUG_ON(!cpvt);
+
+ if (!(cmd = get_ready_cmd(cpvt))) {
+ if (file->f_flags & O_NONBLOCK) {
+ return -EAGAIN;
+ } else {
+ /* Wait here for at most 31ms for a packet to come in
+ * since it should never take longer than that to
+ * transcode.
+ */
+ ret = wait_event_interruptible_timeout(cpvt->waitq,
+ (!list_empty(&cpvt->rx_queue)), HZ/32);
+ if (-ERESTARTSYS == ret) {
+ /* Signal interrupted the wait */
+ return -EINTR;
+ } else if (ret) {
+ /* List went not empty. */
+ cmd = get_ready_cmd(cpvt);
+ } else {
+ /* Timeout... */
+ DTE_PRINTK(wc, INFO, "Timeout while waiting for transcoded packet.\n");
+ WARN_ON(!list_empty(&cpvt->rx_queue));
+ return -ENODATA;
+ }
+ }
+ }
+
+ BUG_ON(!cmd);
+ packet = &cmd->cmd[0];
- wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
-
- wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS;
-
[... 4708 lines stripped ...]
More information about the zaptel-commits
mailing list