Logo Search packages:      
Sourcecode: dahdi-linux version File versions  Download package

base.c

/*
 * Wildcard TC400B Driver
 *
 * Copyright (C) 2006-2009, 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 <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/etherdevice.h>
#include <linux/timer.h>

#include "dahdi/kernel.h"

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
#include <asm/io.h>
#else
#include <linux/io.h>
#endif

/* COMPILE TIME OPTIONS =================================================== */

#define INTERRUPT 0
#define WORKQUEUE 1
#define TASKLET   2

#ifndef DEFERRED_PROCESSING
#     define DEFERRED_PROCESSING WORKQUEUE
#endif

#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 WARN_ALWAYS() 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)
#ifndef WARN_ON_ONCE
#define WARN_ON_ONCE(__condition) do {         \
      static int __once = 1;                 \
      if (unlikely(__condition)) {           \
            if (__once) {                  \
                  __once = 0;            \
                  WARN_ON(0);            \
            }                              \
      }                                      \
} while (0)
#endif
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
/* also added in RHEL kernels with the OpenInfiniband backport: */
#if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,9) || !defined(DEFINE_SPINLOCK)
typedef     unsigned gfp_t;         /* Added in 2.6.14 */
#endif
#endif

/* The total number of active channels over which the driver will start polling
 * the card every 10 ms. */
#define POLLING_CALL_THRESHOLD 40

#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
#define MAX_CHANNEL_PACKETS  5

#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 */

static int debug;
static 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));

#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 MONITOR_LIVE_INDICATION_TYPE 0x75
#define CONFIG_CHANGE_TYPE    0x00
#define CONFIG_CHANNEL_CLASS  0x02
#define CONFIG_DEVICE_CLASS   0x06

/* Individual channel config commands */
#define MAX_FRAME_SIZE 1518
#define SFRAME_SIZE MAX_FRAME_SIZE

#define DRING_SIZE (1 << 7) /* Must be a power of two */
#define DRING_MASK (DRING_SIZE-1)
#define MIN_PACKET_LEN  64

#undef USE_CUSTOM_MEMCACHE

/* Transcoder buffer (tcb) */
struct tcb {
      void *data;
      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;
      /* The number of bytes available in data. */
      int data_len;
      spinlock_t lock;
#ifdef USE_CUSTOM_MEMCACHE
      u32 sentinel;
#endif
};

static inline const struct csm_encaps_hdr *
response_header(struct tcb *cmd)
{
      BUG_ON(!cmd->response);
      return (const struct csm_encaps_hdr *)(cmd)->response->data;
}

static inline void
initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
{
      INIT_LIST_HEAD(&cmd->node);
      init_completion(&cmd->complete);
      cmd->flags = cmd_flags;
      spin_lock_init(&cmd->lock);
#ifdef USE_CUSTOM_MEMCACHE
      cmd->sentinel = 0xdeadbeef;
#endif
}

#ifdef USE_CUSTOM_MEMCACHE

struct my_cache {
      atomic_t outstanding_count;
      spinlock_t lock;
      struct list_head free;
};

static struct tcb *my_cache_alloc(struct my_cache *c, gfp_t alloc_flags)
{
      unsigned long flags;
      struct tcb *cmd;
      spin_lock_irqsave(&c->lock, flags);
      if (!list_empty(&c->free)) {
            cmd = list_entry(c->free.next, struct tcb, node);
            list_del_init(&cmd->node);
            spin_unlock_irqrestore(&c->lock, flags);
      } else {
            spin_unlock_irqrestore(&c->lock, flags);
            cmd = kmalloc(sizeof(*cmd), alloc_flags);
      }
      atomic_inc(&c->outstanding_count);
      return cmd;
}

static void my_cache_free(struct my_cache *c, struct tcb *cmd)
{
      unsigned long flags;
      spin_lock_irqsave(&c->lock, flags);
      list_add_tail(&cmd->node, &c->free);
      spin_unlock_irqrestore(&c->lock, flags);
      atomic_dec(&c->outstanding_count);
}

static struct my_cache *my_cache_create(void)
{
      struct my_cache *c;
      c = kzalloc(sizeof(*c), GFP_KERNEL);
      if (!c)
            return NULL;
      spin_lock_init(&c->lock);
      INIT_LIST_HEAD(&c->free);
      return c;
}

static int my_cache_destroy(struct my_cache *c)
{
      struct tcb *cmd;
      if (atomic_read(&c->outstanding_count)) {
            DTE_DEBUG(DTE_DEBUG_GENERAL,"Leaked %d commands.\n",
                  atomic_read(&c->outstanding_count));
      }
      while (!list_empty(&c->free)) {
            cmd = list_entry(c->free.next, struct tcb, node);
            list_del_init(&cmd->node);
            kfree(cmd);
      }
      kfree(c);
      return 0;
}

static struct my_cache *cmd_cache;

#else

#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. */
static struct kmem_cache *cmd_cache;
#endif

#endif /* USE_CUSTOM_MEMCACHE */

static inline struct tcb *
__alloc_cmd(size_t size, gfp_t alloc_flags, unsigned long cmd_flags)
{
      struct tcb *cmd;

      if (unlikely(size > SFRAME_SIZE))
            return NULL;
      if (size < MIN_PACKET_LEN)
            size = MIN_PACKET_LEN;
#ifdef USE_CUSTOM_MEMCACHE
      cmd = my_cache_alloc(cmd_cache, alloc_flags);
#else
      cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
#endif
      if (likely(cmd)) {
            memset(cmd, 0, sizeof(*cmd));
            cmd->data = kzalloc(size, alloc_flags);
            if (unlikely(!cmd->data)) {
                  kmem_cache_free(cmd_cache, cmd);
                  return NULL;
            }
            cmd->data_len = size;
            initialize_cmd(cmd, cmd_flags);
      }
      return cmd;
}

static struct tcb *
alloc_cmd(size_t size)
{
      return __alloc_cmd(size, GFP_KERNEL, 0);
}

static void
__free_cmd(struct tcb *cmd)
{
      if (cmd)
            kfree(cmd->data);
#ifdef USE_CUSTOM_MEMCACHE
      my_cache_free(cmd_cache, cmd);
#else
      kmem_cache_free(cmd_cache, cmd);
#endif
      return;
}

static void
free_cmd(struct tcb *cmd)
{
      if (cmd->response)
            __free_cmd(cmd->response);
      __free_cmd(cmd);
}

struct channel_stats {
      atomic_t packets_sent;
      atomic_t packets_received;
};

struct channel_pvt {
      spinlock_t lock;  /* Lock for this structure */
      struct wcdte *wc;
      u16 seqno;
      u8 cmd_seqno;
      u8 ssrc;
      u16 timeslot_in_num;    /* DTE timeslot to receive from */
      u16 timeslot_out_num;   /* DTE timeslot to send data to */
      u16 chan_in_num;  /* DTE channel to receive from */
      u16 chan_out_num; /* DTE channel to send data to */
      u32 timestamp;
      struct {
            u8 encoder:1;     /* If we're an encoder */
      };
      struct channel_stats stats;
      struct list_head rx_queue; /* Transcoded packets for this channel. */
};

struct wcdte {
      char board_name[40];
      const char *variety;
      int pos;
      struct list_head node;
      spinlock_t reglock;
      wait_queue_head_t waitq;
      struct semaphore chansem;
#define DTE_READY 1
#define DTE_SHUTDOWN    2
#define DTE_POLLING     3
      unsigned long flags;

      /* This is a device-global list of commands that are waiting to be
       * transmited (and did not fit on the transmit descriptor ring) */
      spinlock_t cmd_list_lock;
      struct list_head cmd_list;
      struct list_head waiting_for_response_list;

      spinlock_t rx_list_lock;
      struct list_head rx_list;
      spinlock_t rx_lock;

      unsigned int seq_num;
      int last_rx_seq_num;
      unsigned char numchannels;
      unsigned char complexname[40];

      /* 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;

      struct dahdi_transcoder *uencode;
      struct dahdi_transcoder *udecode;
      struct channel_pvt *encoders;
      struct channel_pvt *decoders;

#if DEFERRED_PROCESSING == WORKQUEUE
      struct work_struct deferred_work;
#endif

      /*
       * This section contains the members necessary for exporting the
       * network interface to the host system.  This is only used for
       * debugging purposes.
       *
       */
      struct sk_buff_head captured_packets;
      struct net_device *netdev;
      struct net_device_stats net_stats;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
      struct napi_struct napi;
#endif
      struct timer_list watchdog;
      atomic_t open_channels;
      struct timer_list polling;
#if HZ > 100
      unsigned long jiffies_at_last_poll;
#endif
};

#ifdef HAVE_NETDEV_PRIV
struct wcdte_netdev_priv {
      struct wcdte *wc;
};
#endif

static inline struct wcdte *
wcdte_from_netdev(struct net_device *netdev)
{
#ifdef HAVE_NETDEV_PRIV
      struct wcdte_netdev_priv *priv;
      priv = netdev_priv(netdev);
      return priv->wc;
#else
      return netdev->priv;
#endif
}


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);
}

#define DTE_FORMAT_ULAW   0x00
#define DTE_FORMAT_G723_1 0x04
#define DTE_FORMAT_ALAW   0x08
#define DTE_FORMAT_G729A  0x12
#define DTE_FORMAT_UNDEF  0xFF

static inline u8 wctc4xxp_dahdifmt_to_dtefmt(unsigned int fmt)
{
      u8 pt;

      switch (fmt) {
      case DAHDI_FORMAT_G723_1:
            pt = DTE_FORMAT_G723_1;
            break;
      case DAHDI_FORMAT_ULAW:
            pt = DTE_FORMAT_ULAW;
            break;
      case DAHDI_FORMAT_ALAW:
            pt = DTE_FORMAT_ALAW;
            break;
      case DAHDI_FORMAT_G729A:
            pt = DTE_FORMAT_G729A;
            break;
      default:
            pt = DTE_FORMAT_UNDEF;
            break;
      }

      return pt;
}

static struct sk_buff *
tcb_to_skb(struct net_device *netdev, const struct tcb *cmd)
{
      struct sk_buff *skb;
      skb = alloc_skb(cmd->data_len, in_atomic() ? GFP_ATOMIC : GFP_KERNEL);
      if (skb) {
            skb->dev = netdev;
            skb_put(skb, cmd->data_len);
            memcpy(skb->data, cmd->data, cmd->data_len);
            skb->protocol = eth_type_trans(skb, netdev);
      }
      return skb;
}

/**
 * wctc4xxp_skb_to_cmd - Convert a socket buffer (skb) to a tcb
 * @wc: The transcoder that we're going to send this command to.
 * @skb: socket buffer to convert.
 *
 */
static struct tcb *
wctc4xxp_skb_to_cmd(struct wcdte *wc, const struct sk_buff *skb)
{
      const gfp_t alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
      struct tcb *cmd;
      cmd = __alloc_cmd(skb->len, alloc_flags, 0);
      if (cmd) {
            int res;
            cmd->data_len = skb->len;
            res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len);
            if (res) {
                  DTE_PRINTK(WARNING,
                     "Failed call to skb_copy_bits.\n");
                  free_cmd(cmd);
                  cmd = NULL;
            }
      }
      return cmd;
}

static void
wctc4xxp_net_set_multi(struct net_device *netdev)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n",
         __func__, netdev->promiscuity);
}

static int
wctc4xxp_net_up(struct net_device *netdev)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
      netif_poll_enable(netdev);
#else
      napi_enable(&wc->napi);
#endif
      return 0;
}

static int
wctc4xxp_net_down(struct net_device *netdev)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
      netif_poll_disable(netdev);
#else
      napi_disable(&wc->napi);
#endif
      return 0;
}

static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *);

static int
wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      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.
       */
      cmd = wctc4xxp_skb_to_cmd(wc, skb);
      if (cmd) {
            cmd->flags |= DO_NOT_CAPTURE;
            wctc4xxp_transmit_cmd(wc, cmd);
      }

      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;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
static int
wctc4xxp_poll(struct net_device *netdev, int *budget)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      int count = 0;
      int quota = min(netdev->quota, *budget);

      count = wctc4xxp_net_receive(wc, quota);

      *budget -=       count;
      netdev->quota -= count;

      if (!skb_queue_len(&wc->captured_packets)) {
            netif_rx_complete(netdev);
            return 0;
      } else {
            return -1;
      }
}
#else
static int
wctc4xxp_poll(struct napi_struct *napi, int budget)
{
      struct wcdte *wc = container_of(napi, struct wcdte, napi);
      int count;

      count = wctc4xxp_net_receive(wc, budget);

      if (!skb_queue_len(&wc->captured_packets)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
            netif_rx_complete(wc->netdev, &wc->napi);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
            netif_rx_complete(&wc->napi);
#else
            napi_complete(&wc->napi);
#endif
      }
      return count;
}
#endif

static struct net_device_stats *
wctc4xxp_net_get_stats(struct net_device *netdev)
{
      struct wcdte *wc = wcdte_from_netdev(netdev);
      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 = wcdte_from_netdev(netdev);
      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;
}

#ifdef HAVE_NET_DEVICE_OPS
static const struct net_device_ops wctc4xxp_netdev_ops = {
      .ndo_set_multicast_list = &wctc4xxp_net_set_multi,
      .ndo_open = &wctc4xxp_net_up,
      .ndo_stop = &wctc4xxp_net_down,
      .ndo_start_xmit = &wctc4xxp_net_hard_start_xmit,
      .ndo_get_stats = &wctc4xxp_net_get_stats,
      .ndo_do_ioctl = &wctc4xxp_net_ioctl,
};
#endif

/**
 * 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)
{
      int res;
      struct net_device *netdev;
#     ifdef HAVE_NETDEV_PRIV
      struct wcdte_netdev_priv *priv;
#     endif
      const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};

#     ifdef HAVE_NETDEV_PRIV
      netdev = alloc_netdev(sizeof(*priv), wc->board_name, ether_setup);
      if (!netdev)
            return -ENOMEM;
      priv = netdev_priv(netdev);
      priv->wc = wc;
#     else
      netdev = alloc_netdev(0, wc->board_name, ether_setup);
      if (!netdev)
            return -ENOMEM;
      netdev->priv = wc;
#     endif
      memcpy(netdev->dev_addr, our_mac, sizeof(our_mac));

#     ifdef HAVE_NET_DEVICE_OPS
      netdev->netdev_ops = &wctc4xxp_netdev_ops;
#     else
      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;
#     endif

      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

      res = register_netdev(netdev);
      if (res) {
            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
wctc4xxp_net_unregister(struct wcdte *wc)
{
      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;
}


/**
 * 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;

      if (!netdev)
            return;

      /* No need to capture if there isn't anyone listening. */
      if (!(netdev->flags & IFF_UP))
            return;

      if (skb_queue_len(&wc->captured_packets) > MAX_CAPTURED_PACKETS) {
            WARN_ON_ONCE(1);
            return;
      }

      skb = tcb_to_skb(netdev, cmd);
      if (!skb)
            return;

      skb_queue_tail(&wc->captured_packets, skb);
#     if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
      netif_rx_schedule(netdev);
#     elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
      netif_rx_schedule(netdev, &wc->napi);
#     elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
      netif_rx_schedule(&wc->napi);
#     else
      napi_schedule(&wc->napi);
#     endif
      return;
}


/*! In-memory structure shared by the host and the adapter. */
00891 struct wctc4xxp_descriptor {
      __le32 des0;
      __le32 des1;
      __le32 buffer1;
      __le32 container; /* Unused */
} __attribute__((packed));

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)
{
      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;
      int add_padding;

      BUG_ON(!pdev);
      BUG_ON(!dr);

      if (pci_read_config_byte(pdev, 0x0c, &cache_line_size))
            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.
       *
       */
      add_padding =   (0x08 == cache_line_size) ||
                  (0x10 == cache_line_size) ||
                  (0x20 == cache_line_size);
      if (add_padding)
            dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d);

      dr->desc = pci_alloc_consistent(pdev,
                  (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma);

      if (!dr->desc)
            return -ENOMEM;

      memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE);
      for (i = 0; i < DRING_SIZE; ++i) {
            d = wctc4xxp_descriptor(dr, i);
            d->des1 = cpu_to_le32(des1);
      }

      d->des1 |= cpu_to_le32(END_OF_RING);
      dr->direction = direction;
      spin_lock_init(&dr->lock);
      dr->pdev = pdev;
      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)

static 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;
      unsigned long flags;

      WARN_ON(!c);
      len = (c->data_len < MIN_PACKET_LEN) ? MIN_PACKET_LEN : c->data_len;
      if (c->data_len > MAX_FRAME_SIZE) {
            WARN_ON_ONCE(!"Invalid command length passed\n");
            c->data_len = MAX_FRAME_SIZE;
      }

      spin_lock_irqsave(&dr->lock, flags);
      d = wctc4xxp_descriptor(dr, dr->tail);
      WARN_ON(!d);
      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 = 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_irqrestore(&dr->lock, flags);
      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;
      unsigned long flags;
      spin_lock_irqsave(&dr->lock, flags);
      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;
            WARN_ON(c->data_len > SFRAME_SIZE);
      } else {
            c = NULL;
      }
      spin_unlock_irqrestore(&dr->lock, flags);
      return c;
}

static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr)
{
      int count;
      unsigned long flags;
      spin_lock_irqsave(&dr->lock, flags);
      count = dr->count;
      spin_unlock_irqrestore(&dr->lock, flags);
      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
__wctc4xxp_getctl(struct wcdte *wc, unsigned int addr)
{
      return inl(wc->iobase + addr);
}

static inline void
wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
{
      unsigned long flags;
      spin_lock_irqsave(&wc->reglock, flags);
      __wctc4xxp_setctl(wc, addr, val);
      spin_unlock_irqrestore(&wc->reglock, flags);
}

static inline void
wctc4xxp_receive_demand_poll(struct wcdte *wc)
{
      __wctc4xxp_setctl(wc, 0x0010, 0x00000000);
}

static inline void
wctc4xxp_transmit_demand_poll(struct wcdte *wc)
{
      return;
# if 0
      __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);
#endif
}

/* 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)

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 int wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd);

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 void
setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr)
{
      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 void
setup_channel_header(struct channel_pvt *pvt, struct csm_encaps_hdr *hdr)
{
      setup_common_header(pvt->wc, hdr);
      hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE);
      hdr->seq_num = (pvt->cmd_seqno++)&0xf;
      hdr->channel = cpu_to_be16(pvt->chan_in_num);
}

static void
create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class,
      u16 function, const u16 *parameters, const int num_parameters)
{
      struct csm_encaps_hdr *hdr = cmd->data;
      int i;

      if (cmd->response) {
            free_cmd(cmd->response);
            cmd->response = NULL;
      }

      setup_supervisor_header(wc, hdr);

      hdr->length =           LENGTH_WITH_N_PARAMETERS(num_parameters);
      hdr->index =            0;
      hdr->type =       type;
      hdr->class =            class;
      hdr->function =         cpu_to_le16(function);
      hdr->reserved =         0;

      for (i = 0; i < num_parameters; ++i)
            hdr->params[i] = cpu_to_le16(parameters[i]);

      cmd->flags = WAIT_FOR_RESPONSE;
      cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters);
}

static void
create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class,
      u16 function, const u16 *parameters, int num_parameters)
{
      int i;
      struct csm_encaps_hdr *hdr = cmd->data;

      if (cmd->response) {
            free_cmd(cmd->response);
            cmd->response = NULL;
      }

      setup_channel_header(pvt, hdr);

      hdr->length =     LENGTH_WITH_N_PARAMETERS(num_parameters);
      hdr->index =      0;
      hdr->type = type;
      hdr->class =      class;
      hdr->function =   cpu_to_le16(function);
      hdr->reserved =   0;

      for (i = 0; i < num_parameters; ++i)
            hdr->params[i] = cpu_to_le16(parameters[i]);

      cmd->flags = WAIT_FOR_RESPONSE;
      cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters);
}

static int
send_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot,
      u16 *channel_number)
{
      int res;
      const u16 parameters[] = {0x0002, timeslot};

      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, SUPVSR_CREATE_CHANNEL,
            parameters, ARRAY_SIZE(parameters));

      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;

      if (0x0000 != response_header(cmd)->params[0]) {
            /* The DTE failed to create the channel. */
            /* TODO put some debug information here. */
            WARN_ON(1);
            free_cmd(cmd->response);
            cmd->response = NULL;
            return -EIO;
      }

      *channel_number = le16_to_cpu(response_header(cmd)->params[1]);
      free_cmd(cmd->response);
      cmd->response = NULL;
      return 0;
}

static int
send_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x012c, 0x0000};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0411, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_set_spu_clk_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x012c, 0x0000};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0412, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_tdm_select_bus_mode_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0004};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0417, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_set_eth_header_cmd(struct wcdte *wc, struct tcb *cmd,
      const u8 *host_mac, const u8 *assigned_mac)
{
      u16 parameters[8];
      u16 *part;

      parameters[0] = 0x0001;
      part = (u16 *)host_mac;
      parameters[1] = part[0];
      parameters[2] = part[1];
      parameters[3] = part[2];
      part = (u16 *)assigned_mac;
      parameters[4] = part[0];
      parameters[5] = part[1];
      parameters[6] = part[2];
      parameters[7] = 0x0008;

      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0100, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_supvsr_setup_tdm_parms(struct wcdte *wc, struct tcb *cmd,
      u8 bus_number)
{
      const u16 parameters[] = {0x8380, 0x0c00, 0, (bus_number << 2)&0xc};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0407, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_ip_service_config_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0200};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0302, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_arp_service_config_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0001};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0105, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_icmp_service_config_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0xff01};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0304, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_device_set_country_code_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0000};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x041b, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_spu_features_control_cmd(struct wcdte *wc, struct tcb *cmd, u16 options)
{
      const u16 parameters[] = {options};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0013, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_tdm_opt_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0000};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0435, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
send_destroy_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 channel)
{
      int res;
      u16 result;
      const u16 parameters[] = {channel};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0011, parameters,
            ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;
      /* Let's check the response for any error codes.... */
      result = le16_to_cpu(response_header(cmd)->params[0]);
      if (0x0000 != result) {
            DTE_PRINTK(ERR, "Failed to destroy channel %04d (%04x)\n",
                  channel, result);
            return -EIO;
      }
      return 0;
}

static int
send_set_ip_hdr_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd)
{
      int res;
      u16 result;
      struct wcdte *wc = pvt->wc;
      const u16 parameters[] = {0, 0x0045, 0, 0, 0x0040, 0x1180, 0,
            0xa8c0, 0x0309, 0xa8c0, 0x0309,
            cpu_to_be16(pvt->timeslot_out_num + 0x5000),
            cpu_to_be16(pvt->timeslot_in_num + 0x5000),
            0, 0};
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x9000, parameters, ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;
      /* Let's check the response for any error codes.... */
      result = le16_to_cpu(response_header(cmd)->params[0]);
      if (0x0000 != result) {
            DTE_PRINTK(ERR, "Failure in %s (%04x)\n",
                  __func__, result);
            return -EIO;
      }
      return 0;
}

static int
send_voip_vceopt_cmd(struct channel_pvt *pvt, struct tcb *cmd, u16 length)
{
      int res;
      u16 result;
      const u16 parameters[] = {((length << 8)|0x21), 0x1c00, 0x0004, 0, 0};
      struct wcdte *wc = pvt->wc;
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x8001, parameters, ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;
      /* Let's check the response for any error codes.... */
      result = le16_to_cpu(response_header(cmd)->params[0]);
      if (0x0000 != result) {
            DTE_PRINTK(ERR, "Failure in %s (%04x)\n",
                  __func__, result);
            return -EIO;
      }
      return 0;
}

static int
send_voip_tonectl_cmd(struct channel_pvt *pvt, struct tcb *cmd)
{
      int res;
      u16 result;
      const u16 parameters[] = {0};
      struct wcdte *wc = pvt->wc;
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x805b, parameters, ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;
      /* Let's check the response for any error codes.... */
      result = le16_to_cpu(response_header(cmd)->params[0]);
      if (0x0000 != result) {
            DTE_PRINTK(ERR, "Failure in %s (%04x)\n",
                  __func__, result);
            return -EIO;
      }
      return 0;
}

static int
send_voip_dtmfopt_cmd(struct channel_pvt *pvt, struct tcb *cmd)
{
      const u16 parameters[] = {0x0008};
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x8002, parameters, ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
}

static int
send_voip_indctrl_cmd(struct channel_pvt *pvt, struct tcb *cmd)
{
      const u16 parameters[] = {0x0007};
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x8084, parameters, ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
}

static int
send_voip_vopena_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 format)
{
      const u16 parameters[] = {1, ((format<<8)|0x80), 0, 0, 0,
            0x3412, 0x7856};
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x8000, parameters, ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
}

static int
send_voip_vopena_close_cmd(struct channel_pvt *pvt, struct tcb *cmd)
{
      int res;
      const u16 parameters[] = {0};
      create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
            0x8000, parameters, ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
      if (res)
            return res;
      /* Let's check the response for any error codes.... */
      if (0x0000 != response_header(cmd)->params[0]) {
            WARN_ON(1);
            return -EIO;
      }
      return 0;
}

static int
send_ip_options_cmd(struct wcdte *wc, struct tcb *cmd)
{
      const u16 parameters[] = {0x0002};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x0306, parameters,
            ARRAY_SIZE(parameters));
      return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}

static int
_send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, u16 enable, u16
      encoder_channel, u16 decoder_channel, u16 encoder_format,
      u16 decoder_format)
{
      int res;
      const u16 parameters[] = {enable, encoder_channel, encoder_format,
            decoder_channel, decoder_format};
      create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
            CONFIG_DEVICE_CLASS, 0x9322, parameters,
            ARRAY_SIZE(parameters));
      res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
      if (res)
            return res;

      /* Let's check the response for any error codes.... */
      if (0x0000 != response_header(cmd)->params[0]) {
#ifdef USE_CUSTOM_MEMCACHE
            WARN_ON(0xdeadbeef != cmd->response->sentinel);
#endif
            WARN_ON(1);
            return -EIO;
      }
      return 0;
}

static int
send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, const u16
      encoder_channel, const u16 decoder_channel, const u16 encoder_format,
      const u16 decoder_format)
{
      return _send_trans_connect_cmd(wc, cmd, 1, encoder_channel,
            decoder_channel, encoder_format, decoder_format);
}

static int
send_trans_disconnect_cmd(struct wcdte *wc, struct tcb *cmd, const u16
      encoder_channel, const u16 decoder_channel, const u16 encoder_format,
      const u16 decoder_format)
{
      return _send_trans_connect_cmd(wc, cmd, 0, encoder_channel,
            decoder_channel, encoder_format, decoder_format);
}

static struct tcb *
wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc,
      size_t inbytes)
{
      const struct channel_pvt *cpvt = dtc->pvt;
      struct rtp_packet *packet;
      struct tcb *cmd;

      cmd = alloc_cmd(sizeof(*packet) + inbytes);
      if (!cmd)
            return NULL;

      packet = cmd->data;

      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 =            0;
      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,
                              packet->iphdr.ihl);

      /* setup the UDP header */
      packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000);
      packet->udphdr.dest =   cpu_to_be16(cpvt->timeslot_in_num + 0x5000);
      packet->udphdr.len  =   cpu_to_be16(inbytes + sizeof(struct rtphdr) +
                              sizeof(struct udphdr));
      packet->udphdr.check =  0;

      /* Setup the RTP header */
      packet->rtphdr.ver =        2;
      packet->rtphdr.padding =    0;
      packet->rtphdr.extension =  0;
      packet->rtphdr.csrc_count = 0;
      packet->rtphdr.marker =     0;
      packet->rtphdr.type =       wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt);
      packet->rtphdr.seqno =      cpu_to_be16(cpvt->seqno);
      packet->rtphdr.timestamp =  cpu_to_be32(cpvt->timestamp);
      packet->rtphdr.ssrc =       cpu_to_be32(cpvt->ssrc);

      WARN_ON(cmd->data_len > SFRAME_SIZE);
      return cmd;
}
static void
wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
{
      int i;
      struct wctc4xxp_descriptor *d;

      if (!dr || !dr->desc)
            return;

      for (i = 0; i < DRING_SIZE; ++i) {
            d = wctc4xxp_descriptor(dr, i);
            if (d->buffer1) {
                  pci_unmap_single(dr->pdev, 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;
      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;
      unsigned long flags;
      LIST_HEAD(local_list);

      spin_lock_irqsave(&wc->cmd_list_lock, flags);
      list_splice_init(&wc->cmd_list, &local_list);
      list_splice_init(&wc->waiting_for_response_list, &local_list);
      list_splice_init(&wc->rx_list, &local_list);
      spin_unlock_irqrestore(&wc->cmd_list_lock, flags);

      while (!list_empty(&local_list)) {
            cmd = list_entry(local_list.next, struct tcb, node);
            list_del_init(&cmd->node);
            free_cmd(cmd);
      }
}

/**
 * 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)
{
      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
wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd)
{
      unsigned long flags;
      spin_lock_irqsave(&wc->cmd_list_lock, flags);
      list_add_tail(&cmd->node, &wc->waiting_for_response_list);
      spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
}

static void
wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd)
{
      unsigned long flags;
      spin_lock_irqsave(&wc->cmd_list_lock, flags);
      list_del_init(&cmd->node);
      spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
}

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;
            }
            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);
      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 if (0 == res) {
            wctc4xxp_transmit_demand_poll(wc);
      } else {
            /* Unknown return value... */
            WARN_ON(1);
      }
}

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 void
wctc4xxp_init_state(struct channel_pvt *cpvt, int 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;
      cpvt->timeslot_in_num = channel*2;
      cpvt->timeslot_out_num = channel*2;
      if (encoder)
            ++cpvt->timeslot_out_num;
      else
            ++cpvt->timeslot_in_num;
      spin_lock_init(&cpvt->lock);
      INIT_LIST_HEAD(&cpvt->rx_queue);
}

static unsigned int
wctc4xxp_getctl(struct wcdte *wc, unsigned int addr)
{
      unsigned int val;
      unsigned long flags;
      spin_lock_irqsave(&wc->reglock, flags);
      val = __wctc4xxp_getctl(wc, addr);
      spin_unlock_irqrestore(&wc->reglock, flags);
      return val;
}

static void
wctc4xxp_cleanup_channel_private(struct wcdte *wc,
      struct dahdi_transcoder_channel *dtc)
{
      struct tcb *cmd, *temp;
      struct channel_pvt *cpvt = dtc->pvt;
      unsigned long flags;
      LIST_HEAD(local_list);

      spin_lock_irqsave(&cpvt->lock, flags);
      list_splice_init(&cpvt->rx_queue, &local_list);
      dahdi_tc_clear_data_waiting(dtc);
      spin_unlock_irqrestore(&cpvt->lock, flags);

      memset(&cpvt->stats, 0, sizeof(cpvt->stats));
      list_for_each_entry_safe(cmd, temp, &local_list, node) {
            list_del(&cmd->node);
            free_cmd(cmd);
      }
}

static int
wctc4xxp_mark_channel_complement_built(struct wcdte *wc,
      struct dahdi_transcoder_channel *dtc)
{
      int index;
      struct channel_pvt *cpvt = dtc->pvt;
      struct dahdi_transcoder_channel *compl_dtc;
      struct channel_pvt *compl_cpvt;

      BUG_ON(!cpvt);
      index = cpvt->timeslot_in_num/2;
      BUG_ON(index >= wc->numchannels);
      if (cpvt->encoder)
            compl_dtc = &(wc->udecode->channels[index]);
      else
            compl_dtc = &(wc->uencode->channels[index]);

      /* It shouldn't already have been built... */
      WARN_ON(dahdi_tc_is_built(compl_dtc));
      compl_dtc->built_fmts = dtc->dstfmt | dtc->srcfmt;
      compl_cpvt = compl_dtc->pvt;
      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
            "dtc: %p is the complement to %p\n", compl_dtc, dtc);
      compl_cpvt->chan_in_num = cpvt->chan_out_num;
      compl_cpvt->chan_out_num = cpvt->chan_in_num;
      dahdi_tc_set_built(compl_dtc);
      wctc4xxp_cleanup_channel_private(wc, dtc);

      return 0;
}

static int
do_channel_allocate(struct dahdi_transcoder_channel *dtc)
{
      struct channel_pvt *cpvt = dtc->pvt;
      struct wcdte *wc = cpvt->wc;
      u8 wctc4xxp_srcfmt; /* Digium Transcoder Engine Source Format */
      u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */
      int res;

#ifndef DEBUG_WCTC4XXP
      down(&wc->chansem);
#else
      if (down_interruptible(&wc->chansem))
            return -EINTR;
#endif

      /* Check again to see if the channel was built after grabbing the
       * channel semaphore, in case the previous holder of the semaphore
       * built this channel as a complement to itself. */
      if (dahdi_tc_is_built(dtc)) {
            up(&wc->chansem);
            DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
              "Allocating channel %p which is already built.\n", dtc);
            return 0;
      }

      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
            "Entering %s for channel %p.\n", __func__, dtc);
      /* Anything on the rx queue now is old news... */
      wctc4xxp_cleanup_channel_private(wc, dtc);
      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
            "Allocating a new channel: %p.\n", dtc);
      wctc4xxp_srcfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt);
      wctc4xxp_dstfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->dstfmt);
      res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt,
            wctc4xxp_dstfmt);
      if (res) {
            /* There was a problem creating the channel.... */
            up(&wc->chansem);
            return res;
      }
      /* Mark this channel as built */
      dahdi_tc_set_built(dtc);
      dtc->built_fmts = dtc->dstfmt | dtc->srcfmt;
      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
        "Channel %p has dstfmt=%x and srcfmt=%x\n", dtc, dtc->dstfmt,
        dtc->srcfmt);
      /* Mark the channel complement (other half of encoder/decoder pair) as
       * built */
      res = wctc4xxp_mark_channel_complement_built(wc, dtc);
      up(&wc->chansem);
      dahdi_transcoder_alert(dtc);
      return res;
}

static void
wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask)
{
      wc->intmask = intmask;
      wctc4xxp_setctl(wc, 0x0038, intmask);
}

static void
wctc4xxp_enable_interrupts(struct wcdte *wc)
{
      wctc4xxp_setintmask(wc, 0x000180c0);
}

static void
wctc4xxp_disable_interrupts(struct wcdte *wc)
{
      /* Disable interrupts */
      wctc4xxp_setintmask(wc, 0x00000000);
      wctc4xxp_setctl(wc, 0x0084, 0x00000000);
}

static void
wctc4xxp_enable_polling(struct wcdte *wc)
{
      set_bit(DTE_POLLING, &wc->flags);
      mod_timer(&wc->polling, jiffies + 1);
      wctc4xxp_disable_interrupts(wc);
}

static int
wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
{
      struct wcdte *wc = ((struct channel_pvt *)(dtc->pvt))->wc;

      if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
            /* The shudown flags can also be set if there is a
             * catastrophic failure. */
            return -EIO;
      }

      atomic_inc(&wc->open_channels);
      if (atomic_read(&wc->open_channels) > POLLING_CALL_THRESHOLD) {
            if (!test_bit(DTE_POLLING, &wc->flags))
                  wctc4xxp_enable_polling(wc);
      }

      if (dahdi_tc_is_built(dtc)) {
            DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
              "Allocating channel %p which is already built.\n", dtc);
            return 0;
      }
      return do_channel_allocate(dtc);
}

static void
wctc4xxp_disable_polling(struct wcdte *wc)
{
      clear_bit(DTE_POLLING, &wc->flags);
      wctc4xxp_enable_interrupts(wc);
}

static int
wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
{
      int res;
      int index;
      /* This is the 'complimentary channel' to dtc.  I.e., if dtc is an
       * encoder, compl_dtc is the decoder and vice-versa */
      struct dahdi_transcoder_channel *compl_dtc;
      struct channel_pvt *compl_cpvt;
      struct channel_pvt *cpvt = dtc->pvt;
      struct wcdte *wc = cpvt->wc;
      int packets_received, packets_sent;

      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;
      }

#ifndef DEBUG_WCTC4XXP
      down(&wc->chansem);
#else
      if (down_interruptible(&wc->chansem))
            return -EINTR;
#endif

      atomic_dec(&wc->open_channels);
      if (atomic_read(&wc->open_channels) < POLLING_CALL_THRESHOLD) {
            if (test_bit(DTE_POLLING, &wc->flags))
                  wctc4xxp_disable_polling(wc);
      }

      packets_received = atomic_read(&cpvt->stats.packets_received);
      packets_sent = atomic_read(&cpvt->stats.packets_sent);
            
      if ((packets_sent - packets_received) > 5) {
            DTE_DEBUG(DTE_DEBUG_GENERAL, "%s channel %d sent %d packets " 
                  "and received %d packets.\n", (cpvt->encoder) ? 
                  "encoder" : "decoder", cpvt->chan_out_num,
                  packets_sent, packets_received);
      }

      /* Remove any packets that are waiting on the outbound queue. */
      wctc4xxp_cleanup_channel_private(wc, dtc);
      index = cpvt->timeslot_in_num/2;
      BUG_ON(index >= wc->numchannels);
      if (cpvt->encoder)
            compl_dtc = &(wc->udecode->channels[index]);
      else
            compl_dtc = &(wc->uencode->channels[index]);
      BUG_ON(!compl_dtc);
      if (!dahdi_tc_is_built(compl_dtc)) {
            DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
                  "Releasing a channel that was never built.\n");
            res = 0;
            goto error_exit;
      }
      /* If the channel complement (other half of the encoder/decoder pair) is
       * being used. */
      if (dahdi_tc_is_busy(compl_dtc)) {
            res = 0;
            goto error_exit;
      }
      res = wctc4xxp_destroy_channel_pair(wc, cpvt);
      if (res)
            goto error_exit;

      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %p\n", dtc);
      /* Mark this channel as not built */
      dahdi_tc_clear_built(dtc);
      dtc->built_fmts = 0;
      cpvt->chan_in_num = INVALID;
      cpvt->chan_out_num = INVALID;
      /* Mark the channel complement as not built */
      dahdi_tc_clear_built(compl_dtc);
      compl_dtc->built_fmts = 0;
      compl_cpvt = compl_dtc->pvt;
      compl_cpvt->chan_in_num = INVALID;
      compl_cpvt->chan_out_num = INVALID;
error_exit:
      up(&wc->chansem);
      return res;
}

static inline struct tcb*
get_ready_cmd(struct dahdi_transcoder_channel *dtc)
{
      struct channel_pvt *cpvt = dtc->pvt;
      struct tcb *cmd;
      unsigned long flags;
      spin_lock_irqsave(&cpvt->lock, flags);
      if (!list_empty(&cpvt->rx_queue)) {
            WARN_ON(!dahdi_tc_is_data_waiting(dtc));
            cmd = list_entry(cpvt->rx_queue.next, struct tcb, node);
            list_del_init(&cmd->node);
      } else {
            cmd = NULL;
      }
      if (list_empty(&cpvt->rx_queue))
            dahdi_tc_clear_data_waiting(dtc);
      spin_unlock_irqrestore(&cpvt->lock, flags);
      return cmd;
}

static int
wctc4xxp_handle_receive_ring(struct wcdte *wc)
{
      struct tcb *cmd;
      unsigned long flags;
      unsigned int count = 0;

      /* If we can't grab this lock, another thread must already be checking
       * the receive ring...so we should just finish up, and we'll try again
       * later. */
#if defined(spin_trylock_irqsave)
      if (!spin_trylock_irqsave(&wc->rx_lock, flags))
            return 0;
#else
      if (spin_is_locked(&wc->rx_lock))
            return 0;
      spin_lock_irqsave(&wc->rx_lock, flags);
#endif

      while ((cmd = wctc4xxp_retrieve(wc->rxd))) {
            ++count;
            spin_lock(&wc->rx_list_lock);
            list_add_tail(&cmd->node, &wc->rx_list);
            spin_unlock(&wc->rx_list_lock);
            cmd = __alloc_cmd(SFRAME_SIZE, GFP_ATOMIC, 0);
            if (!cmd) {
                  DTE_PRINTK(ERR, "Out of memory in %s.\n", __func__);
            } else {
                  if (wctc4xxp_submit(wc->rxd, cmd)) {
                        DTE_PRINTK(ERR, "Failed submit in %s\n",
                              __func__);
                        free_cmd(cmd);
                  }
            }
      }
      spin_unlock_irqrestore(&wc->rx_lock, flags);
      return count;
}

static void
__wctc4xxp_polling(struct wcdte *wc)
{
      if (wctc4xxp_handle_receive_ring(wc))
            schedule_work(&wc->deferred_work);
}

static void
wctc4xxp_polling(unsigned long data)
{
      struct wcdte *wc = (struct wcdte *)data;
      __wctc4xxp_polling(wc);
      if (test_bit(DTE_POLLING, &wc->flags))
            mod_timer(&wc->polling, jiffies + 1);
}


/* Called with a buffer in which to copy a transcoded frame. */
static ssize_t
wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
{
      ssize_t ret;
      struct dahdi_transcoder_channel *dtc = file->private_data;
      struct channel_pvt *cpvt = dtc->pvt;
      struct wcdte *wc = cpvt->wc;
      struct tcb *cmd;
      struct rtp_packet *packet;
      ssize_t payload_bytes;

      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;
      }

      cmd = get_ready_cmd(dtc);
      if (!cmd) {
            if (file->f_flags & O_NONBLOCK) {
                  return -EAGAIN;
            } else {
                  ret = wait_event_interruptible(dtc->ready,
                        dahdi_tc_is_data_waiting(dtc));
                  if (-ERESTARTSYS == ret) {
                        /* Signal interrupted the wait */
                        return -EINTR;
                  } else {
                        /* List went not empty. */
                        cmd = get_ready_cmd(dtc);
                  }
            }
      }

      BUG_ON(!cmd);
      packet = cmd->data;

      payload_bytes = be16_to_cpu(packet->udphdr.len) -
            sizeof(struct rtphdr) - sizeof(struct udphdr);

      if (count < payload_bytes) {
            if (printk_ratelimit()) {
                  DTE_PRINTK(ERR,
                    "Cannot copy %zd bytes into %zd byte user " \
                    "buffer.\n", payload_bytes, count);
            }
            free_cmd(cmd);
            return -EFBIG;
      }

      atomic_inc(&cpvt->stats.packets_received);

      if (unlikely(copy_to_user(frame, &packet->payload[0], payload_bytes))) {
            DTE_PRINTK(ERR, "Failed to copy data in %s\n", __func__);
            free_cmd(cmd);
            return -EFAULT;
      }

      free_cmd(cmd);

      return payload_bytes;
}

/* Called with a frame in the srcfmt to be transcoded into the dstfmt. */
static ssize_t
wctc4xxp_write(struct file *file, const char __user *frame,
      size_t count, loff_t *ppos)
{
      struct dahdi_transcoder_channel *dtc = file->private_data;
      struct channel_pvt *cpvt = dtc->pvt;
      struct wcdte *wc = cpvt->wc;
      struct tcb *cmd;

      BUG_ON(!cpvt);
      BUG_ON(!wc);

      if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags)))
            return -EIO;

      if (!test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags))
            return -EAGAIN;

      if (count < 2) {
            DTE_DEBUG(DTE_DEBUG_GENERAL,
               "Cannot request to transcode a packet that is less than " \
               "2 bytes.\n");
            return -EINVAL;
      }

      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;
      }

      if (DAHDI_FORMAT_G723_1 == dtc->srcfmt) {
            if ((G723_5K_BYTES != count) && (G723_6K_BYTES != count)) {
                  DTE_DEBUG(DTE_DEBUG_GENERAL,
                     "Trying to transcode packet into G723 format " \
                     "that is %Zu bytes instead of the expected " \
                     "%d/%d bytes.\n", count, G723_5K_BYTES,
                     G723_6K_BYTES);
                  return -EINVAL;
            }
            cpvt->timestamp += G723_SAMPLES;
      } else if (DAHDI_FORMAT_G723_1 == dtc->dstfmt) {
            cpvt->timestamp = G723_SAMPLES;
      } else {
            /* Same for ulaw and alaw */
            cpvt->timestamp += G729_SAMPLES;
      }

      cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count);
      if (!cmd)
            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;

      DTE_DEBUG(DTE_DEBUG_RTP_TX,
          "Sending packet of %Zu byte on channel (%p).\n", count, dtc);

      atomic_inc(&cpvt->stats.packets_sent);
      wctc4xxp_transmit_cmd(wc, cmd);

      if (test_bit(DTE_POLLING, &wc->flags)) {
#if HZ == 100
            __wctc4xxp_polling(wc);
#else
            if (jiffies != wc->jiffies_at_last_poll) {
                  wc->jiffies_at_last_poll = jiffies;
                  __wctc4xxp_polling(wc);
            }
#endif
      }


      return count;
}

static void
wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
{
      struct tcb *cmd;
      struct csm_encaps_hdr *hdr;
      cmd = __alloc_cmd(sizeof(*hdr), ALLOC_FLAGS, 0);
      if (!cmd) {
            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;

      wctc4xxp_transmit_cmd(wc, cmd);
}

static void
do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
{
      const struct csm_encaps_hdr *listhdr, *rxhdr;
      struct tcb *pos, *temp;
      unsigned long flags;
      u32 handled = 0;
      rxhdr = cmd->data;
      if (0xffff == rxhdr->channel) {
            /* We received a duplicate response. */
            if (rxhdr->seq_num == wc->last_rx_seq_num) {
                  free_cmd(cmd);
                  return;
            }
            wc->last_rx_seq_num = rxhdr->seq_num;
      }

      spin_lock_irqsave(&wc->cmd_list_lock, flags);
      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)) {

                  spin_lock(&pos->lock);
                  list_del_init(&pos->node);
                  pos->flags &= ~(__WAIT_FOR_RESPONSE);
                  pos->response = cmd;
                  /* If this isn't TX_COMPLETE yet, then this packet will
                   * be completed in service_tx_ring. */
                  if (pos->flags & TX_COMPLETE)
                        complete(&pos->complete);
                  spin_unlock(&pos->lock);
                  handled = 1;

                  break;
            }
      }
      spin_unlock_irqrestore(&wc->cmd_list_lock, flags);

      if (!handled) {
            DTE_DEBUG(DTE_DEBUG_GENERAL,
                  "Freeing unhandled response ch:(%04x)\n",
                  be16_to_cpu(rxhdr->channel));
            free_cmd(cmd);
      }
}

static void
do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
{
      const struct csm_encaps_hdr *listhdr, *rxhdr;
      struct tcb *pos, *temp;
      unsigned long flags;

      rxhdr = cmd->data;

      spin_lock_irqsave(&wc->cmd_list_lock, flags);
      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));
                  WARN_ON(!(pos->flags & TX_COMPLETE));
                  list_del_init(&pos->node);
                  WARN_ON(!(pos->flags & TX_COMPLETE));
                  complete(&pos->complete);
            } else if ((listhdr->seq_num == rxhdr->seq_num) &&
                     (listhdr->channel == rxhdr->channel)) {
                  spin_lock(&pos->lock);
                  if (pos->flags & __WAIT_FOR_RESPONSE) {
                        pos->flags &= ~(__WAIT_FOR_ACK);
                        spin_unlock(&pos->lock);
                  } else {
                        list_del_init(&pos->node);

                        if (pos->flags & DO_NOT_AUTO_FREE) {
                              WARN_ON(!(pos->flags & TX_COMPLETE));
                              complete(&pos->complete);
                              spin_unlock(&pos->lock);
                        } else {
                              spin_unlock(&pos->lock);
                              free_cmd(pos);
                        }
                  }
                  break;
            }
      }
      spin_unlock_irqrestore(&wc->cmd_list_lock, flags);

      /* There is never a reason to store up the ack packets. */
      free_cmd(cmd);
}

static inline int
is_response(const struct csm_encaps_hdr *hdr)
{
      return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0;
}

static void
print_command(struct wcdte *wc, const struct tcb *cmd)
{
      int i, curlength;
      const struct csm_encaps_hdr *hdr = cmd->data;
      char *buffer;
      const int BUFFER_SIZE = 1024;
      int parameters = ((hdr->length - 8)/sizeof(__le16));

      buffer = kzalloc(BUFFER_SIZE + 1, GFP_ATOMIC);
      if (!buffer) {
            DTE_PRINTK(DEBUG, "Failed print_command\n");
            return;
      }
      curlength = snprintf(buffer, BUFFER_SIZE,
            "opcode: %04x seq: %02x control: %02x "
            "channel: %04x ", be16_to_cpu(hdr->op_code),
            hdr->seq_num, hdr->control, be16_to_cpu(hdr->channel));
      curlength += snprintf(buffer + curlength, BUFFER_SIZE - curlength,
            "length: %02x index: %02x type: %02x "
            "class: %02x function: %04x",
            hdr->length, hdr->index, hdr->type, hdr->class,
            le16_to_cpu(hdr->function));
      for (i = 0; i < parameters; ++i) {
            curlength += snprintf(buffer + curlength,
                  BUFFER_SIZE - curlength, " %04x",
                  le16_to_cpu(hdr->params[i]));
      }
      DTE_PRINTK(DEBUG, "%s\n", buffer);
      kfree(buffer);
}

static void
receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
{
      const struct csm_encaps_hdr *hdr = cmd->data;

      if (!(hdr->control & MESSAGE_PACKET)) {
            if (!(hdr->control & SUPPRESS_ACK))
                  wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel);

            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)) &&
                        (hdr->params[1] != le16_to_cpu(0x010c))) {
                        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 if (MONITOR_LIVE_INDICATION_TYPE == hdr->type) {
                  DTE_PRINTK(WARNING, "Received diagnostic message:\n");
                  print_command(wc, cmd);
                  free_cmd(cmd);
            } else {
                  DTE_PRINTK(WARNING,
                    "Unknown command type received. %02x\n", hdr->type);
                  free_cmd(cmd);
            }
      } else {
            do_rx_ack_packet(wc, cmd);
      }
}

static void
queue_rtp_packet(struct wcdte *wc, struct tcb *cmd)
{
      unsigned index;
      struct dahdi_transcoder_channel *dtc;
      struct channel_pvt *cpvt;
      struct rtp_packet *packet = cmd->data;
      unsigned long flags;

      if (unlikely(ip_fast_csum((void *)(&packet->iphdr),
            packet->iphdr.ihl))) {
            DTE_DEBUG(DTE_DEBUG_GENERAL,
                  "Invalid checksum in RTP packet %04x\n",
                  ip_fast_csum((void *)(&packet->iphdr),
                  packet->iphdr.ihl));
            free_cmd(cmd);
            return;
      }

      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_irqsave(&cpvt->lock, flags);
      list_add_tail(&cmd->node, &cpvt->rx_queue);
      dahdi_tc_set_data_waiting(dtc);
      spin_unlock_irqrestore(&cpvt->lock, flags);
      dahdi_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_DEBUG(DTE_DEBUG_GENERAL,
               "Unknown packet protocol recieved: %04x.\n",
               be16_to_cpu(ethhdr->h_proto));
            free_cmd(cmd);
      }
}

static inline void service_tx_ring(struct wcdte *wc)
{
      struct tcb *cmd;
      unsigned long flags;
      while ((cmd = wctc4xxp_retrieve(wc->txd))) {
            spin_lock_irqsave(&cmd->lock, flags);
            cmd->flags |= TX_COMPLETE;
            if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) {
                  /* If we're not waiting for an ACK or Response from
                   * the DTE, this message should not be sitting on any
                   * lists. */
                  WARN_ON(!list_empty(&cmd->node));
                  if (DO_NOT_AUTO_FREE & cmd->flags) {
                        spin_unlock_irqrestore(&cmd->lock, flags);
                        WARN_ON(!(cmd->flags & TX_COMPLETE));
                        complete(&cmd->complete);
                  } else {
                        spin_unlock_irqrestore(&cmd->lock, flags);
                        free_cmd(cmd);
                  }
            } else {
                  spin_unlock_irqrestore(&cmd->lock, flags);
            }

            /* 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_irqsave(&wc->cmd_list_lock, flags);
            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_irqrestore(&wc->cmd_list_lock, flags);

            if (cmd)
                  wctc4xxp_transmit_cmd(wc, cmd);
      }
}

static inline void service_rx_ring(struct wcdte *wc)
{
      struct tcb *cmd;
      unsigned long flags;
      LIST_HEAD(local_list);
      spin_lock_irqsave(&wc->rx_list_lock, flags);
      list_splice_init(&wc->rx_list, &local_list);
      spin_unlock_irqrestore(&wc->rx_list_lock, flags);

      /*
       * Process the received packets
       */
      while (!list_empty(&local_list)) {
            cmd = container_of(local_list.next, struct tcb, node);
            list_del_init(&cmd->node);

            wctc4xxp_net_capture_cmd(wc, cmd);
            wctc4xxp_receiveprep(wc, cmd);
      }
      wctc4xxp_receive_demand_poll(wc);
}

static inline void service_dte(struct wcdte *wc)
{
      service_tx_ring(wc);
      service_rx_ring(wc);
}


#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void deferred_work_func(void *param)
{
      struct wcdte *wc = param;
#else
static void deferred_work_func(struct work_struct *work)
{
      struct wcdte *wc = container_of(work, struct wcdte, deferred_work);
#endif
      service_dte(wc);
}

DAHDI_IRQ_HANDLER(wctc4xxp_interrupt)
{
      struct wcdte *wc = dev_id;
      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 = __wctc4xxp_getctl(wc, 0x0028);

      ints &= wc->intmask;

      if (!ints)
            return IRQ_NONE;

      if (likely(ints & NORMAL_INTERRUPTS)) {
            reg = 0;
            if (ints & TX_COMPLETE_INTERRUPT)
                  reg |= TX_COMPLETE_INTERRUPT;

            if (ints & RX_COMPLETE_INTERRUPT) {
                  wctc4xxp_handle_receive_ring(wc);
                  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)
                  DTE_PRINTK(INFO, "Fatal Bus Error INT\n");

            if ((ints & 0x00000100) && debug)
                  DTE_PRINTK(INFO, "Receive Stopped INT\n");

            if ((ints & 0x00000080) && debug) {
                  DTE_PRINTK(INFO, "Receive Desciptor Unavailable INT " \
                      "(%d)\n", wctc4xxp_getcount(wc->rxd));
            }

            if ((ints & 0x00000020) && debug)
                  DTE_PRINTK(INFO, "Transmit Under-flow INT\n");

            if ((ints & 0x00000008) && debug)
                  DTE_PRINTK(INFO, "Jabber Timer Time-out INT\n");

            if ((ints & 0x00000002) && debug)
                  DTE_PRINTK(INFO, "Transmit Processor Stopped INT\n");

            /* Clear all the pending interrupts. */
            __wctc4xxp_setctl(wc, 0x0028, ints);
      }
      return IRQ_HANDLED;
}

static int
wctc4xxp_hardware_init(struct wcdte *wc)
{
      /* Hardware stuff */
      u32 reg;
      unsigned long newjiffies;
      u8 cache_line_size;
      const u32 DEFAULT_PCI_ACCESS = 0xfff80000;

      /* Enable I/O Access */
      pci_read_config_dword(wc->pdev, 0x0004, &reg);
      reg |= 0x00000007;
      pci_write_config_dword(wc->pdev, 0x0004, reg);

      if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size))
            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);

      wctc4xxp_setctl(wc, 0x0000, reg | 0x60000);

      /* Configure watchdogs, access, etc */
      wctc4xxp_setctl(wc, 0x0030, 0x00280040);
      wctc4xxp_setctl(wc, 0x0078, 0x00000013);
      reg = wctc4xxp_getctl(wc, 0x00fc);
      wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
      reg = wctc4xxp_getctl(wc, 0x00fc);
      return 0;
}

static void
wctc4xxp_start_dma(struct wcdte *wc)
{
      int res;
      int i;
      u32 reg;
      struct tcb *cmd;

      for (i = 0; i < DRING_SIZE; ++i) {
            cmd = alloc_cmd(SFRAME_SIZE);
            if (!cmd) {
                  WARN_ALWAYS();
                  return;
            }
            WARN_ON(SFRAME_SIZE != cmd->data_len);
            res = wctc4xxp_submit(wc->rxd, cmd);
            if (res) {
                  /* When we're starting the DMA, we should always be
                   * able to fill the ring....so something is wrong
                   * here. */
                  WARN_ALWAYS();
                  free_cmd(cmd);
                  break;
            }
      }
      wmb();
      wctc4xxp_setctl(wc, 0x0020, wc->txd->desc_dma);
      wctc4xxp_setctl(wc, 0x0018, wc->rxd->desc_dma);

      /* Start receiver/transmitter */
      reg = wctc4xxp_getctl(wc, 0x0030);
      wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002);
      wctc4xxp_receive_demand_poll(wc);
      reg = wctc4xxp_getctl(wc, 0x0028);
      wctc4xxp_setctl(wc, 0x0028, reg);

}

static void
wctc4xxp_stop_dma(struct wcdte *wc)
{
      /* Disable interrupts and reset */
      unsigned int reg;
      unsigned long newjiffies;
      /* Disable interrupts */
      wctc4xxp_setintmask(wc, 0x00000000);
      wctc4xxp_setctl(wc, 0x0084, 0x00000000);
      wctc4xxp_setctl(wc, 0x0048, 0x00000000);
      /* Reset the part to be on the safe side */
      reg = wctc4xxp_getctl(wc, 0x0000);
      reg |= 0x00000001;
      wctc4xxp_setctl(wc, 0x0000, reg);

      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);
}


#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
wctc4xxp_read_phy(struct wcdte *wc, int location)
{
      int i;
      long mdio_addr = 0x0048;
      int read_cmd = (0xf6 << 10) | (1 << 5) | location;
      int retval = 0;

      /* Establish sync by sending at least 32 logic ones. */
      for (i = 32; i >= 0; --i) {
            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;

            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) {
            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;
}

static void
wctc4xxp_write_phy(struct wcdte *wc, int location, int value)
{
      int i;
      int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value;
      long mdio_addr = 0x0048;

      /* Establish sync by sending 32 logic ones. */
      for (i = 32; i >= 0; --i) {
            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;
            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) {
            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
wctc4xxp_wait_for_link(struct wcdte *wc)
{
      int reg;
      unsigned int delay_count = 0;
      do {
            reg = wctc4xxp_getctl(wc, 0x00fc);
            msleep(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)
{
      unsigned int byteloc;
      unsigned int last_byteloc;
      unsigned int length;
      struct tcb *cmd;

      byteloc = 17;

      cmd = alloc_cmd(SFRAME_SIZE);
      if (!cmd)
            return -ENOMEM;

      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;
}

static int
wctc4xxp_turn_off_booted_led(struct wcdte *wc)
{
      int ret = 0;
      int reg;
      /* Turn off auto negotiation */
      wctc4xxp_write_phy(wc, 0, 0x2100);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n",
         wctc4xxp_read_phy(wc, 0));

      /* Set reset */
      wctc4xxp_setctl(wc, 0x00A0, 0x04000000);

      /* Wait 4 ms to ensure processor reset */
      msleep(4);

      /* Clear reset */
      wctc4xxp_setctl(wc, 0x00A0, 0x04080000);

      /* Wait for the ethernet link */
      ret = wctc4xxp_wait_for_link(wc);
      if (ret)
            return ret;

      /* Turn off booted LED */
      wctc4xxp_setctl(wc, 0x00A0, 0x04084000);
      reg = wctc4xxp_getctl(wc, 0x00fc);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "LINK STATUS: reg(0xfc) = %X\n", reg);

      reg = wctc4xxp_getctl(wc, 0x00A0);

      return ret;
}

static void
wctc4xxp_turn_on_booted_led(struct wcdte *wc)
{
      wctc4xxp_setctl(wc, 0x00A0, 0x04080000);
}

static int
wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware)
{
      int ret;

      wctc4xxp_turn_off_booted_led(wc);

      ret = wctc4xxp_load_firmware(wc, firmware);
      if (ret)
            return ret;

      wctc4xxp_turn_on_booted_led(wc);

      DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n");
      return 0;
}

static int
setup_half_channel(struct channel_pvt *pvt, struct tcb *cmd, u16 length)
{
      if (send_set_ip_hdr_channel_cmd(pvt, cmd))
            return -EIO;
      if (send_voip_vceopt_cmd(pvt, cmd, length))
            return -EIO;
      if (send_voip_tonectl_cmd(pvt, cmd))
            return -EIO;
      if (send_voip_dtmfopt_cmd(pvt, cmd))
            return -EIO;
      if (send_voip_indctrl_cmd(pvt, cmd))
            return -EIO;
      return 0;
}

static int
wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
      u8 simple, u8 complicated)
{
      struct channel_pvt *encoder_pvt, *decoder_pvt;
      u16 encoder_timeslot, decoder_timeslot;
      u16 encoder_channel, decoder_channel;
      u16 length;
      struct tcb *cmd;

      cmd = alloc_cmd(SFRAME_SIZE);
      if (!cmd)
            return -ENOMEM;

      BUG_ON(!wc || !cpvt);
      if (cpvt->encoder) {
            encoder_timeslot = cpvt->timeslot_in_num;
            decoder_timeslot = cpvt->timeslot_out_num;
      } else {
            u8 temp;
            encoder_timeslot = cpvt->timeslot_out_num;
            decoder_timeslot = cpvt->timeslot_in_num;
            temp = simple;
            simple = complicated;
            complicated = temp;
      }

      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
         "DTE is using the following channels encoder_channel: " \
         "%d decoder_channel: %d\n", encoder_channel, decoder_channel);

      BUG_ON(encoder_timeslot/2 >= wc->numchannels);
      BUG_ON(decoder_timeslot/2 >= wc->numchannels);
      encoder_pvt = wc->uencode->channels[encoder_timeslot/2].pvt;
      decoder_pvt = wc->udecode->channels[decoder_timeslot/2].pvt;
      BUG_ON(!encoder_pvt);
      BUG_ON(!decoder_pvt);

      WARN_ON(encoder_timeslot == decoder_timeslot);
      /* First, let's create two channels, one for the simple -> complex
       * encoder and another for the complex->simple decoder. */
      if (send_create_channel_cmd(wc, cmd, encoder_timeslot,
            &encoder_channel))
            goto error_exit;

      if (send_create_channel_cmd(wc, cmd, decoder_timeslot,
            &decoder_channel))
            goto error_exit;

      length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
            (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;

      WARN_ON(encoder_channel == decoder_channel);
      /* Now set all the default parameters for the encoder. */
      encoder_pvt->chan_in_num = encoder_channel;
      encoder_pvt->chan_out_num = decoder_channel;
      if (setup_half_channel(encoder_pvt, cmd, length))
            goto error_exit;

      /* And likewise for the decoder. */
      decoder_pvt->chan_in_num = decoder_channel;
      decoder_pvt->chan_out_num = encoder_channel;
      if (setup_half_channel(decoder_pvt, cmd, length))
            goto error_exit;

      if (send_trans_connect_cmd(wc, cmd, encoder_channel,
            decoder_channel, complicated, simple))
            goto error_exit;
      if (send_voip_vopena_cmd(encoder_pvt, cmd, complicated))
            goto error_exit;
      if (send_voip_vopena_cmd(decoder_pvt, cmd, simple))
            goto error_exit;

      DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
        "DTE has completed setup and connected the " \
        "two channels together.\n");

      free_cmd(cmd);
      return 0;
error_exit:
      free_cmd(cmd);
      return -EIO;
}

static int
wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt)
{
      struct dahdi_transcoder_channel *dtc1, *dtc2;
      struct channel_pvt *encoder_pvt, *decoder_pvt;
      int chan1, chan2, timeslot1, timeslot2;
      struct tcb *cmd;

      cmd = alloc_cmd(SFRAME_SIZE);
      if (!cmd)
            return -ENOMEM;

      if (cpvt->encoder) {
            chan1 = cpvt->chan_in_num;
            timeslot1 = cpvt->timeslot_in_num;
            chan2 = cpvt->chan_out_num;
            timeslot2 = cpvt->timeslot_out_num;
      } else {
            chan1 = cpvt->chan_out_num;
            timeslot1 = cpvt->timeslot_out_num;
            chan2 = cpvt->chan_in_num;
            timeslot2 = cpvt->timeslot_in_num;
      }

      if (timeslot1/2 >= wc->numchannels || timeslot2/2 >= wc->numchannels) {
            DTE_PRINTK(WARNING,
             "Invalid channel numbers in %s. chan1:%d chan2: %d\n",
             __func__, timeslot1/2, timeslot2/2);
            return 0;
      }

      dtc1 = &(wc->uencode->channels[timeslot1/2]);
      dtc2 = &(wc->udecode->channels[timeslot2/2]);
      encoder_pvt = dtc1->pvt;
      decoder_pvt = dtc2->pvt;

      if (send_voip_vopena_close_cmd(encoder_pvt, cmd))
            goto error_exit;
      if (send_voip_vopena_close_cmd(decoder_pvt, cmd))
            goto error_exit;
      if (send_trans_disconnect_cmd(wc, cmd, chan1, chan2, 0, 0))
            goto error_exit;
      if (send_destroy_channel_cmd(wc, cmd, chan1))
            goto error_exit;
      if (send_destroy_channel_cmd(wc, cmd, chan2))
            goto error_exit;

      free_cmd(cmd);
      return 0;
error_exit:
      free_cmd(cmd);
      return -1;
}


static int
__wctc4xxp_setup_channels(struct wcdte *wc)
{
      struct tcb *cmd;
      int tdm_bus;

      cmd = alloc_cmd(SFRAME_SIZE);
      if (!cmd)
            return -ENOMEM;

      if (send_set_arm_clk_cmd(wc, cmd))
            goto error_exit;

      if (send_set_spu_clk_cmd(wc, cmd))
            goto error_exit;

      if (send_tdm_select_bus_mode_cmd(wc, cmd))
            goto error_exit;

      for (tdm_bus = 0; tdm_bus < 4; ++tdm_bus) {
            if (send_supvsr_setup_tdm_parms(wc, cmd, tdm_bus))
                  goto error_exit;
      }

      if (send_set_eth_header_cmd(wc, cmd, src_mac, dst_mac))
            goto error_exit;

      if (send_ip_service_config_cmd(wc, cmd))
            goto error_exit;

      if (send_arp_service_config_cmd(wc, cmd))
            goto error_exit;

      if (send_icmp_service_config_cmd(wc, cmd))
            goto error_exit;

      if (send_device_set_country_code_cmd(wc, cmd))
            goto error_exit;

      if (send_spu_features_control_cmd(wc, cmd, 0x02))
            goto error_exit;

      if (send_ip_options_cmd(wc, cmd))
            goto error_exit;

      if (send_spu_features_control_cmd(wc, cmd, 0x04))
            goto error_exit;

      if (send_tdm_opt_cmd(wc, cmd))
            goto error_exit;

      free_cmd(cmd);
      return 0;
error_exit:
      free_cmd(cmd);
      return -1;
}

static int
wctc4xxp_setup_channels(struct wcdte *wc)
{
      int ret;
#ifndef DEBUG_WCTC4XXP
      down(&wc->chansem);
#else
      if (down_interruptible(&wc->chansem))
            return -EINTR;
#endif
      ret = __wctc4xxp_setup_channels(wc);
      up(&wc->chansem);

      return ret;
}

static void wctc4xxp_setup_file_operations(struct file_operations *fops)
{
      fops->owner = THIS_MODULE;
      fops->read =  wctc4xxp_read;
      fops->write = wctc4xxp_write;
}

static int
initialize_channel_pvt(struct wcdte *wc, int encoder,
      struct channel_pvt **cpvt)
{
      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, encoder, chan, wc);
      return 0;
}

static int
initialize_transcoder(struct wcdte *wc, unsigned int srcfmts,
      unsigned int dstfmts, struct channel_pvt *pvts,
      struct dahdi_transcoder **zt)
{
      int chan;
      *zt = dahdi_transcoder_alloc(wc->numchannels);
      if (!(*zt))
            return -ENOMEM;
      (*zt)->srcfmts = srcfmts;
      (*zt)->dstfmts = dstfmts;
      (*zt)->allocate = wctc4xxp_operation_allocate;
      (*zt)->release = wctc4xxp_operation_release;
      wctc4xxp_setup_file_operations(&((*zt)->fops));
      for (chan = 0; chan < wc->numchannels; ++chan)
            (*zt)->channels[chan].pvt = &pvts[chan];
      return 0;
}

static int initialize_encoders(struct wcdte *wc, unsigned int complexfmts)
{
      int res;
      res = initialize_channel_pvt(wc, 1, &wc->encoders);
      if (res)
            return res;

      res = initialize_transcoder(wc, DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW,
            complexfmts, wc->encoders, &wc->uencode);
      if (res)
            return res;
      sprintf(wc->uencode->name, "DTE Encoder");
      return res;
}

static int
initialize_decoders(struct wcdte *wc, unsigned int complexfmts)
{
      int res;
      res = initialize_channel_pvt(wc, 0, &wc->decoders);
      if (res)
            return res;

      res = initialize_transcoder(wc, complexfmts,
            DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW,
            wc->decoders, &wc->udecode);
      if (res)
            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;
      int reschedule_timer = 0;

      service_tx_ring(wc);

      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);
                        cmd->flags &= ~(TX_COMPLETE);
                  } 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);
                        reschedule_timer = 1;
                  }
            }
      }
      spin_unlock(&wc->cmd_list_lock);

      if (list_empty(&cmds_to_retry) && reschedule_timer)
            mod_timer(&wc->watchdog, jiffies + HZ/2);
      else if (!list_empty(&cmds_to_retry))
            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, &cur->node);
                  break;
            } else {
                  ++pos;
            }
      }
      /* If we didn't already add the new entry to the list, add it now */
      if (list_empty(&wc->node))
            list_add_tail(&wc->node, &wctc4xxp_list);
      spin_unlock(&wctc4xxp_list_lock);
      return pos;
}

struct wctc4xxp_desc {
      const char *short_name;
      const char *long_name;
};

static struct wctc4xxp_desc wctc400p = {
      .short_name = "tc400b",
      .long_name = "Wildcard TC400P+TC400M",
};

static struct wctc4xxp_desc wctce400 = {
      .short_name = "tce400",
      .long_name = "Wildcard TCE400+TC400M",
};

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_dahdi_fw_tc400m_bin_size;
      extern u8 _binary_dahdi_fw_tc400m_bin_start[];
#else
      static const char tc400m_firmware[] = "dahdi-fw-tc400m.bin";
#endif

      /* ------------------------------------------------------------------
       * Setup the pure software constructs internal to this driver.
       * --------------------------------------------------------------- */

      wc = kzalloc(sizeof(*wc), GFP_KERNEL);
      if (!wc)
            return -ENOMEM;

      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;
      wc->last_rx_seq_num  = -1;

      init_MUTEX(&wc->chansem);
      spin_lock_init(&wc->reglock);
      spin_lock_init(&wc->cmd_list_lock);
      spin_lock_init(&wc->rx_list_lock);
      spin_lock_init(&wc->rx_lock);
      INIT_LIST_HEAD(&wc->cmd_list);
      INIT_LIST_HEAD(&wc->waiting_for_response_list);
      INIT_LIST_HEAD(&wc->rx_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;
      }

      init_waitqueue_head(&wc->waitq);

      if (pci_set_dma_mask(wc->pdev, DMA_BIT_MASK(32))) {
            release_region(wc->iobase, 0xff);
            DTE_PRINTK(WARNING, "No suitable DMA available.\n");
            return -EIO;
      }

      wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL);
      if (!wc->txd) {
            res = -ENOMEM;
            goto error_exit_swinit;
      }

      res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd,
            0xe0800000, DMA_TO_DEVICE);
      if (res)
            goto error_exit_swinit;

      wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL);
      if (!wc->rxd) {
            res = -ENOMEM;
            goto error_exit_swinit;
      }

      res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0,
            DMA_FROM_DEVICE);
      if (res)
            goto error_exit_swinit;

#if defined(HOTPLUG_FIRMWARE)
      res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev);
      if (res || !firmware) {
            DTE_PRINTK(ERR,
              "Firmware %s not available from userspace. (%d)\n",
              tc400m_firmware, res);
            goto error_exit_swinit;
      }
#else
      embedded_firmware.data = _binary_dahdi_fw_tc400m_bin_start;
      embedded_firmware.size = (size_t) &_binary_dahdi_fw_tc400m_bin_size;
#endif

      wctc4xxp_firmware_ver = firmware->data[0];
      wctc4xxp_firmware_ver_minor = firmware->data[16];
      g729_numchannels = firmware->data[1];
      g723_numchannels = firmware->data[2];

      min_numchannels = min(g723_numchannels, g729_numchannels);

      if (!mode || strlen(mode) < 4) {
            sprintf(wc->complexname, "G.729a / G.723.1");
            complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
            wc->numchannels = min_numchannels;
      } else if (mode[3] == '9') {  /* "G.729" */
            sprintf(wc->complexname, "G.729a");
            complexfmts = DAHDI_FORMAT_G729A;
            wc->numchannels = g729_numchannels;
      } else if (mode[3] == '3') {  /* "G.723.1" */
            sprintf(wc->complexname, "G.723.1");
            complexfmts = DAHDI_FORMAT_G723_1;
            wc->numchannels = g723_numchannels;
      } else {
            sprintf(wc->complexname, "G.729a / G.723.1");
            complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1;
            wc->numchannels = min_numchannels;
      }

      res = initialize_encoders(wc, complexfmts);
      if (res)
            goto error_exit_swinit;
      res = initialize_decoders(wc, complexfmts);
      if (res)
            goto error_exit_swinit;

      if (DTE_DEBUG_NETWORK_IF & debug) {
            res = wctc4xxp_net_register(wc);
            if (res)
                  goto error_exit_swinit;
      }

#     if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
      wc->watchdog.function = wctc4xxp_watchdog;
      wc->watchdog.data = (unsigned long)wc;
      init_timer(&wc->watchdog);
#     else
      setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc);
#     endif

#     if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
      wc->polling.function = wctc4xxp_polling;
      wc->polling.data = (unsigned long)wc;
      init_timer(&wc->polling);
#     else
      setup_timer(&wc->polling, wctc4xxp_polling, (unsigned long)wc);
#     endif

      /* ------------------------------------------------------------------
       * Load the firmware and start the DTE.
       * --------------------------------------------------------------- */

      res = pci_enable_device(pdev);
      if (res) {
            DTE_PRINTK(ERR, "Failed to enable device.\n");
            goto error_exit_swinit;;
      }
      pci_set_master(pdev);
      pci_set_drvdata(pdev, wc);
      res = request_irq(pdev->irq, wctc4xxp_interrupt,
            DAHDI_IRQ_SHARED, wc->board_name, wc);
      if (res) {
            DTE_PRINTK(ERR, "Unable to request IRQ %d\n", pdev->irq);
            if (firmware != &embedded_firmware)
                  release_firmware(firmware);
            goto error_exit_hwinit;
      }
      res = wctc4xxp_hardware_init(wc);
      if (res) {
            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;

      res = wctc4xxp_setup_channels(wc);
      if (res)
            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);

      reg = wctc4xxp_getctl(wc, 0x00fc);

      DTE_DEBUG(DTE_DEBUG_GENERAL,
         "debug: (post-boot) Reg fc is %08x\n", reg);

      DTE_PRINTK(INFO, "Installed a Wildcard TC: %s \n", wc->variety);
      DTE_DEBUG(DTE_DEBUG_GENERAL, "Operating in DEBUG mode.\n");
      dahdi_transcoder_register(wc->uencode);
      dahdi_transcoder_register(wc->udecode);

      return 0;

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);
      kfree(wc->encoders);
      kfree(wc->decoders);
      dahdi_transcoder_free(wc->uencode);
      dahdi_transcoder_free(wc->udecode);
      wctc4xxp_cleanup_descriptor_ring(wc->txd);
      kfree(wc->txd);
      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 wctc4xxp_cleanup_channels(struct wcdte *wc)
{
      int i;
      struct dahdi_transcoder_channel *dtc_en, *dtc_de;

      for (i = 0; i < wc->numchannels; ++i) {
            dtc_en = &(wc->uencode->channels[i]);
            wctc4xxp_cleanup_channel_private(wc, dtc_en);

            dtc_de = &(wc->udecode->channels[i]);
            wctc4xxp_cleanup_channel_private(wc, dtc_de);
      }
}

static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev)
{
      struct wcdte *wc = pci_get_drvdata(pdev);

      if (!wc)
            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))
            del_timer_sync(&wc->watchdog);

      /* This should already be stopped, but it doesn't hurt to make sure. */
      clear_bit(DTE_POLLING, &wc->flags);
      if (del_timer_sync(&wc->polling))
            del_timer_sync(&wc->polling);

      wctc4xxp_net_unregister(wc);

      /* Stop any DMA */
      wctc4xxp_stop_dma(wc);

      /* In case hardware is still there */
      wctc4xxp_disable_interrupts(wc);

      free_irq(pdev->irq, wc);

      /* There isn't anything that would run in the workqueue that will wait
       * on an interrupt. */

      dahdi_transcoder_unregister(wc->udecode);
      dahdi_transcoder_unregister(wc->uencode);

      /* Free Resources */
      release_region(wc->iobase, 0xff);
      wctc4xxp_cleanup_descriptor_ring(wc->txd);
      kfree(wc->txd);
      wctc4xxp_cleanup_descriptor_ring(wc->rxd);
      kfree(wc->rxd);

      wctc4xxp_cleanup_command_list(wc);
      wctc4xxp_cleanup_channels(wc);

      pci_set_drvdata(pdev, NULL);

      dahdi_transcoder_free(wc->uencode);
      dahdi_transcoder_free(wc->udecode);
      kfree(wc->encoders);
      kfree(wc->decoders);
      kfree(wc);
}

static struct pci_device_id 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 */
      { 0 }
};

MODULE_DEVICE_TABLE(pci, wctc4xxp_pci_tbl);

static struct pci_driver wctc4xxp_driver = {
      .name = "wctc4xxp",
      .probe = wctc4xxp_init_one,
      .remove = __devexit_p(wctc4xxp_remove_one),
      .id_table = wctc4xxp_pci_tbl,
};

static int __init wctc4xxp_init(void)
{
      int res;
      unsigned long cache_flags;

#if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22))
      cache_flags = SLAB_HWCACHE_ALIGN | SLAB_STORE_USER | SLAB_DEBUG_FREE;
#else
      cache_flags = SLAB_HWCACHE_ALIGN;
#endif

#ifdef USE_CUSTOM_MEMCACHE
      cmd_cache = my_cache_create();
#else
#     if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
      cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb),
                  0, cache_flags, NULL, NULL);
#     else
      cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb),
                  0, cache_flags, NULL);
#     endif
#endif

      if (!cmd_cache)
            return -ENOMEM;
      spin_lock_init(&wctc4xxp_list_lock);
      INIT_LIST_HEAD(&wctc4xxp_list);
      res = dahdi_pci_module(&wctc4xxp_driver);
      if (res) {
#ifdef USE_CUSTOM_MEMCACHE
            my_cache_destroy(cmd_cache);
#else
            kmem_cache_destroy(cmd_cache);
#endif
            return -ENODEV;
      }
      return 0;
}

static void __exit wctc4xxp_cleanup(void)
{
      pci_unregister_driver(&wctc4xxp_driver);
#ifdef USE_CUSTOM_MEMCACHE
      my_cache_destroy(cmd_cache);
#else
      kmem_cache_destroy(cmd_cache);
#endif
}

module_param(debug, int, S_IRUGO | S_IWUSR);
module_param(mode, charp, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(mode, "'g729', 'g723.1', or 'any'.  Default 'any'.");
MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver");
MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
MODULE_LICENSE("GPL");

module_init(wctc4xxp_init);
module_exit(wctc4xxp_cleanup);

Generated by  Doxygen 1.6.0   Back to index