[zaptel-commits] kpfleming: branch 1.4 r4483 - in /branches/1.4/kernel: ./ wctc4xxp/
SVN commits to the Zaptel project
zaptel-commits at lists.digium.com
Wed Aug 13 20:57:02 CDT 2008
Author: kpfleming
Date: Wed Aug 13 20:57:01 2008
New Revision: 4483
URL: http://svn.digium.com/view/zaptel?view=rev&rev=4483
Log:
backport new transcoder interface and driver from DAHDI
Removed:
branches/1.4/kernel/wctc4xxp/codec_test.c
Modified:
branches/1.4/kernel/wctc4xxp/Kbuild
branches/1.4/kernel/wctc4xxp/Makefile
branches/1.4/kernel/wctc4xxp/base.c
branches/1.4/kernel/zaptel-base.c
branches/1.4/kernel/zaptel.h
branches/1.4/kernel/zttranscode.c
Modified: branches/1.4/kernel/wctc4xxp/Kbuild
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/Kbuild?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/Kbuild (original)
+++ branches/1.4/kernel/wctc4xxp/Kbuild Wed Aug 13 20:57:01 2008
@@ -8,7 +8,7 @@
EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
endif
-wctc4xxp-objs := base.o
+wctc4xxp-objs := base.o
ifneq ($(HOTPLUG_FIRMWARE),yes)
wctc4xxp-objs += $(FIRM_DIR)/zaptel-fw-tc400m.o
Modified: branches/1.4/kernel/wctc4xxp/Makefile
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/Makefile?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/Makefile (original)
+++ branches/1.4/kernel/wctc4xxp/Makefile Wed Aug 13 20:57:01 2008
@@ -3,14 +3,4 @@
# For newer kernels, Kbuild will be included directly by the kernel
# build system.
include $(src)/Kbuild
-
-else
-
-tests: codec_test
-
-codec_test: codec_test.c ../zaptel.h
- $(CC) -o $@ $< $(CFLAGS)
-
-clean:
- rm -rf codec_test
endif
Modified: branches/1.4/kernel/wctc4xxp/base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/base.c?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/base.c (original)
+++ branches/1.4/kernel/wctc4xxp/base.c Wed Aug 13 20:57:01 2008
@@ -1,9 +1,7 @@
/*
* Wildcard TC400B Driver
*
- * Written by John Sloan <jsloan at digium.com>
- *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -26,86 +24,154 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/mman.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/semaphore.h>
#include <linux/jiffies.h>
-#include <linux/workqueue.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
+
+#include "zaptel.h"
+
+/* COMPILE TIME OPTIONS =================================================== */
+
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET 2
+
+#ifndef DEFERRED_PROCESSING
+# define DEFERRED_PROCESSING WORKQUEUE
#endif
-#include "zaptel.h"
-
-/* #define USE_TEST_HW */
-#define USE_TDM_CONFIG
-#define QUIET_DSP
-
-#define WC_MAX_IFACES 128
-
-#define NUM_CARDS 24
-#define NUM_EC 4
-
-/* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
-#define NUM_CHANNELS 120
-
-#define DTE_FORMAT_ULAW 0x00
-#define DTE_FORMAT_G723_1 0x04
-#define DTE_FORMAT_ALAW 0x08
-#define DTE_FORMAT_G729A 0x12
-#define DTE_FORMAT_UNDEF 0xFF
-
-#define G729_LENGTH 20
-#define G723_LENGTH 30
-
-#define G729_SAMPLES 160 /* G.729 */
-#define G723_SAMPLES 240 /* G.723.1 */
-
-#define G729_BYTES 20 /* G.729 */
-#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
-#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
-#define G723_SID_BYTES 4 /* G.723.1 SID frame */
-
-#define ACK_SPACE 20
-
-#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
-#define MAX_RCV_COMMANDS 16
-
-/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
-#define BOOT_CMD_LEN 1500
-#define OTHER_CMD_LEN 300
-
-#define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */
-
-#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
-
-#define SFRAME_SIZE MAX_COMMAND_LEN
-
-#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
-
-#define MDIO_SHIFT_CLK 0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB 0x00000
-#define MDIO_ENB_IN 0x40000
-#define MDIO_DATA_READ 0x80000
-
-#define RCV_CSMENCAPS 1
-#define RCV_RTP 2
-#define RCV_CSMENCAPS_ACK 3
-#define RCV_OTHER 99
-
-
-/* TDM Commands */
+
+#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() WARN_ON(1)
+
+#define DTE_PRINTK(_lvl, _fmt, _args...) \
+ printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args)
+
+#define DTE_DEBUG(_dbgmask, _fmt, _args...) \
+ if ((debug & _dbgmask) == (_dbgmask)) { \
+ printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args); \
+ } \
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define WARN_ON_ONCE(__condition) do { \
+ static int __once = 1; \
+ if (unlikely(__condition)) { \
+ if (__once) { \
+ __once = 0; \
+ WARN_ON(0); \
+ } \
+ } \
+} while(0)
+#endif
+
+#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
+#define MAX_CHANNEL_PACKETS 5 /* Never let more than 5 outstanding packets exist for any channel. */
+
+#define G729_LENGTH 20
+#define G723_LENGTH 30
+
+#define G729_SAMPLES 160 /* G.729 */
+#define G723_SAMPLES 240 /* G.723.1 */
+
+#define G729_BYTES 20 /* G.729 */
+#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
+#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
+#define G723_SID_BYTES 4 /* G.723.1 SID frame */
+
+#define MAX_CAPTURED_PACKETS 5000
+
+/* The following bit fields are used to set the various debug levels. */
+#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */
+#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */
+#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */
+#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */
+#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */
+#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */
+#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */
+
+int debug;
+char *mode;
+
+static spinlock_t wctc4xxp_list_lock;
+static struct list_head wctc4xxp_list;
+
+#define ETH_P_CSM_ENCAPS 0x889B
+
+struct rtphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 csrc_count:4;
+ __u8 extension:1;
+ __u8 padding:1;
+ __u8 ver:2;
+ __u8 type:7;
+ __u8 marker:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver:2;
+ __u8 padding:1;
+ __u8 extension:1;
+ __u8 csrc_count:4;
+ __u8 marker:1;
+ __u8 type:7;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __be16 seqno;
+ __be32 timestamp;
+ __be32 ssrc;
+} __attribute__((packed));
+
+struct rtp_packet {
+ struct ethhdr ethhdr;
+ struct iphdr iphdr;
+ struct udphdr udphdr;
+ struct rtphdr rtphdr;
+ __u8 payload[0];
+}__attribute__((packed));
+
+/* Ethernet packet type for communication control information to the DTE. */
+struct csm_encaps_hdr {
+ struct ethhdr ethhdr;
+ /* CSM_ENCAPS HEADER */
+ __be16 op_code;
+ __u8 seq_num;
+ __u8 control;
+ __be16 channel;
+ /* COMMON PART OF PAYLOAD HEADER */
+ __u8 length;
+ __u8 index;
+ __u8 type;
+ __u8 class;
+ __le16 function;
+ __le16 reserved;
+ __le16 params[0];
+} __attribute__((packed));
+
+struct csm_create_channel_cmd {
+ struct csm_encaps_hdr hdr;
+ __le16 channel_type;
+ __le16 timeslot;
+} __attribute__((packed));
+
#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30
#define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -181,17 +247,26 @@
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \
0x02,0x00 }
-/* Supervisor channel commands */
-#define CMD_MSG_CREATE_CHANNEL_LEN 32
-#define CMD_MSG_CREATE_CHANNEL(s,t) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \
- 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) }
+#define CONTROL_PACKET_OPCODE 0x0001
+/* Control bits */
+#define LITTLE_ENDIAN 0x01
+#define SUPPRESS_ACK 0x40
+#define MESSAGE_PACKET 0x80
+
+#define SUPERVISOR_CHANNEL 0xffff
+
+/* Supervisor function codes */
+#define SUPVSR_CREATE_CHANNEL 0x0010
+
+#define CONFIG_CHANGE_TYPE 0x00
+#define CONFIG_DEVICE_CLASS 0x06
+
#define CMD_MSG_QUERY_CHANNEL_LEN 30
#define CMD_MSG_QUERY_CHANNEL(s,t) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \
(t&0x00FF), ((t&0xFF00) >> 8) }
+
#define CMD_MSG_TRANS_CONNECT_LEN 38
#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -242,303 +317,227 @@
0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \
0x00,0x00, 0x00,0x00 }
-/* CPU ACK command */
-#define CMD_MSG_ACK_LEN 20
-#define CMD_MSG_ACK(s,c) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) }
-
-/* Wrapper for RTP packets */
-#define CMD_MSG_IP_UDP_RTP_LEN 54
-#define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, \
- 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, \
- 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, \
- 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,(s&0xFF)}
-
-#define CMD_MSG_DW_WRITE_LEN 38
-#define CMD_MSG_DW_WRITE(s,a,d) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01,s&0x0F,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x00,0x00, \
- ((a>>24)&0x00FF),((a>>16)&0x00FF), ((a>>8)&0x00FF),(a&0x00FF), \
- ((d>>24)&0x00FF),((d>>16)&0x00FF), ((d>>8)&0x00FF),(d&0x00FF) }
-
-#define CMD_MSG_FORCE_ALERT_LEN 32
-#define CMD_MSG_FORCE_ALERT(s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x09,0x04, 0x00,0x00, \
- 0x24,0x00, 0x00,0x00 }
-
-#define zt_send_cmd(wc, command, length, hex) \
- ({ \
- int ret = 0; \
- do { \
- if (ret == 2) \
- { \
- wc->ztsnd_rtx++; \
- if (hex == 0x0010) \
- wc->ztsnd_0010_rtx++; \
- } \
- down(&wc->cmdqsem); \
- wc->last_command_sent = hex; \
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \
- printk("wcdte error: cmdq is full.\n"); \
- else { \
- unsigned char fifo[OTHER_CMD_LEN] = command; \
- int i; \
- wc->cmdq[wc->cmdq_wndx].cmdlen = length; \
- for (i = 0; i < length; i++) \
- wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \
- wc->last_seqno = fifo[16]; \
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
- } \
- __transmit_demand(wc); \
- up(&wc->cmdqsem); \
- if (hex == 0x0000) \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2); \
- else { \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
- if (wc->dsp_crashed) \
- return 1; \
- } \
- if (ret == 1) \
- return(1); \
- } while (ret == 2); \
- })
-
-
-struct cmdq {
- unsigned int cmdlen;
- unsigned char cmd[MAX_COMMAND_LEN];
+#define SFRAME_SIZE 320
+
+/* Transcoder buffer (tcb) */
+struct tcb {
+ /* First field so that is aligned by default. */
+ u8 cmd[SFRAME_SIZE];
+ struct list_head node;
+ unsigned long timeout;
+ unsigned long retries;
+ /* NOTE: these flags aren't bit fields because some of the flags are
+ * combinations of the other ones. */
+#define DO_NOT_AUTO_FREE (1 << 0)
+#define TX_COMPLETE (1 << 1)
+#define DO_NOT_CAPTURE (1 << 2)
+#define __WAIT_FOR_ACK (1 << 3)
+#define __WAIT_FOR_RESPONSE (1 << 4)
+#define DTE_CMD_TIMEOUT (1 << 5)
+#define WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE)
+#define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE)
+ unsigned long flags;
+ struct tcb *response;
+ struct completion complete;
+ struct timer_list timer;
+ void *data;
+ /* The number of bytes available in data. */
+ int data_len;
};
+static inline void *hdr_from_cmd(struct tcb *cmd) {
+ return cmd->data;
+}
+
+static inline void
+initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ INIT_LIST_HEAD(&cmd->node);
+ init_completion(&cmd->complete);
+ cmd->flags = cmd_flags;
+ cmd->data = &cmd->cmd[0];
+ cmd->data_len = SFRAME_SIZE;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/*! Used to allocate commands to submit to the dte. */
+kmem_cache_t *cmd_cache;
+#else
+/*! Used to allocate commands to submit to the dte. */
+struct kmem_cache *cmd_cache;
+#endif
+
+static inline struct tcb *
+__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags)
+{
+ struct tcb *cmd;
+
+ cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
+ if (likely(cmd)) {
+ initialize_cmd(cmd, cmd_flags);
+ }
+ return cmd;
+}
+
+static struct tcb *
+alloc_cmd(void)
+{
+ return __alloc_cmd(GFP_KERNEL, 0);
+}
+
+static void
+__free_cmd(struct tcb *cmd)
+{
+ if (cmd->data != &cmd->cmd[0]) {
+ kfree(cmd->data);
+ }
+ kmem_cache_free(cmd_cache, cmd);
+ return;
+}
+
+static void
+free_cmd(struct tcb *cmd)
+{
+ if (cmd->response) {
+ __free_cmd(cmd->response);
+ }
+ __free_cmd(cmd);
+}
+
+typedef enum { DECODER=0, ENCODER, } encode_t;
+
+struct channel_stats {
+ atomic_t packets_sent;
+ atomic_t packets_received;
+};
+
+struct channel_pvt {
+ spinlock_t lock; /* Lock for this structure */
+ encode_t encoder; /* If we're an encoder */
+ struct wcdte *wc;
+
+ unsigned int timestamp;
+ unsigned int seqno;
+
+ unsigned int cmd_seqno;
+
+ unsigned int timeslot_in_num; /* DTE channel on which results will be received from */
+ unsigned int timeslot_out_num; /* DTE channel to send data to */
+
+ unsigned int chan_in_num; /* DTE channel on which results will be received from */
+ unsigned int chan_out_num; /* DTE channel to send data to */
+
+ struct channel_stats stats;
+
+ u16 last_dte_seqno;
+ unsigned int wctc4xxp_seqno_rcv;
+
+ unsigned char ssrc;
+ struct list_head rx_queue; /* Transcoded packets for this channel. */
+};
+
struct wcdte {
- struct pci_dev *dev;
- char *variety;
- unsigned int intcount;
- unsigned int rxints;
- unsigned int txints;
- unsigned int intmask;
+ char board_name[40];
+ const char *variety;
int pos;
- int freeregion;
- int rdbl;
- int tdbl;
int cards;
+ struct list_head node;
spinlock_t reglock;
- wait_queue_head_t regq;
- int rcvflags;
-
+ wait_queue_head_t waitq;
struct semaphore chansem;
- struct semaphore cmdqsem;
- struct cmdq cmdq[MAX_COMMANDS];
- unsigned int cmdq_wndx;
- unsigned int cmdq_rndx;
-
- unsigned int last_seqno;
- unsigned int last_rseqno;
- unsigned int last_command_sent;
- unsigned int last_rcommand;
- unsigned int last_rparm1;
+#define DTE_READY 1
+#define DTE_SHUTDOWN 2
+ unsigned long flags;
+
+ spinlock_t cmd_list_lock;
+ /* This is a device-global list of commands that are waiting to be
+ * transmited (and did not fit on the transmit descriptor ring) */
+ struct list_head cmd_list;
+ struct list_head waiting_for_response_list;
+
unsigned int seq_num;
- long timeout;
-
- unsigned int dsp_crashed;
- unsigned int dumping;
-
- unsigned int ztsnd_rtx;
- unsigned int ztsnd_0010_rtx;
-
unsigned char numchannels;
unsigned char complexname[40];
- unsigned long iobase;
- dma_addr_t readdma;
- dma_addr_t writedma;
- dma_addr_t descripdma;
- volatile unsigned int *writechunk; /* Double-word aligned write memory */
- volatile unsigned int *readchunk; /* Double-word aligned read memory */
- volatile unsigned int *descripchunk; /* Descriptors */
+ /* This section contains the members necessary to communicate with the
+ * physical interface to the transcoding engine. */
+ struct pci_dev *pdev;
+ unsigned int intmask;
+ unsigned long iobase;
+ struct wctc4xxp_descriptor_ring *txd;
+ struct wctc4xxp_descriptor_ring *rxd;
- int wqueints;
- struct workqueue_struct *dte_wq;
- struct work_struct dte_work;
-
struct zt_transcoder *uencode;
struct zt_transcoder *udecode;
+ struct channel_pvt *encoders;
+ struct channel_pvt *decoders;
+
+#if DEFERRED_PROCESSING == WORKQUEUE
+ struct work_struct deferred_work;
+#endif
+
+ /*
+ * This section contains the members necessary for exporting the
+ * network interface to the host system. This is only used for
+ * debugging purposes.
+ *
+ */
+ struct sk_buff_head captured_packets;
+ struct net_device *netdev;
+ struct net_device_stats net_stats;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ struct napi_struct napi;
+#endif
+ struct timer_list watchdog;
+
};
-struct wcdte_desc {
- char *name;
- int flags;
-};
-
-static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 };
-static struct wcdte_desc wctce400 = { "Wildcard TCE400+TC400M", 0 };
-
-static struct wcdte *ifaces[WC_MAX_IFACES];
-
-
-
-/*
- * The following is the definition of the state structure
- * used by the G.721/G.723 encoder and decoder to preserve their internal
- * state between successive calls. The meanings of the majority
- * of the state structure fields are explained in detail in the
- * CCITT Recommendation G.721. The field names are essentially indentical
- * to variable names in the bit level description of the coding algorithm
- * included in this Recommendation.
- */
-struct dte_state {
- int encoder; /* If we're an encoder */
- struct wcdte *wc;
-
- unsigned int timestamp;
- unsigned int seqno;
-
- unsigned int cmd_seqno;
-
- unsigned int timeslot_in_num; /* DTE chennel on which results we be received from */
- unsigned int timeslot_out_num; /* DTE channel to send data to */
-
- unsigned int chan_in_num; /* DTE chennel on which results we be received from */
- unsigned int chan_out_num; /* DTE channel to send data to */
+static inline void wctc4xxp_set_ready(struct wcdte *wc) {
+ set_bit(DTE_READY, &wc->flags);
+}
+static inline int wctc4xxp_is_ready(struct wcdte *wc) {
+ return test_bit(DTE_READY, &wc->flags);
+}
+
+#if 1
+ /* \todo This macro is a candidate for removal. It's still here because of
+ * how the commands are passed to this zt_send_cmd */
+#define wctc4xxp_send_cmd(wc, command) ({ \
+ int __res; \
+ u8 _cmd[] = command; \
+ struct tcb *cmd; \
+ if (!(cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \
+ return -ENOMEM; \
+ BUG_ON(sizeof(_cmd) > SFRAME_SIZE); \
+ memcpy(cmd->data, _cmd, sizeof(_cmd)); \
+ cmd->data_len = sizeof(_cmd); \
+ __res = __wctc4xxp_send_cmd(wc, cmd); \
+ __res; \
+})
+#define wctc4xxp_create_cmd(wc, command) ({ \
+ u8 _command[] = command; \
+ struct tcb *_cmd; \
+ if (!(_cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \
+ return -ENOMEM; \
+ BUG_ON(sizeof(_command) > SFRAME_SIZE); \
+ memcpy(_cmd->data, _command, sizeof(_command)); \
+ _cmd->data_len = sizeof(_command); \
+ _cmd; \
+})
+#endif
+
+#define DTE_FORMAT_ULAW 0x00
+#define DTE_FORMAT_G723_1 0x04
+#define DTE_FORMAT_ALAW 0x08
+#define DTE_FORMAT_G729A 0x12
+#define DTE_FORMAT_UNDEF 0xFF
+
+static inline u8 wctc4xxp_zapfmt_to_dtefmt(unsigned int fmt)
+{
+ u8 pt;
- unsigned int packets_sent;
- unsigned int packets_received;
-
- unsigned int last_dte_seqno;
- unsigned int dte_seqno_rcv;
-
- unsigned char ssrc;
-};
-
-
-static struct zt_transcoder *uencode;
-static struct zt_transcoder *udecode;
-static struct dte_state *encoders;
-static struct dte_state *decoders;
-static int debug = 0;
-static int debug_des = 0; /* Set the number of descriptor packet bytes to output on errors, 0 disables output */
-static int debug_des_cnt = 0; /* Set the number of times descriptor packets are displayed before the output is disabled */
-static int force_alert = 0;
-static int debug_notimeout = 0;
-static char *mode;
-static int debug_packets = 0;
-
-static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2);
-static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2);
-static int __wcdte_setup_channels(struct wcdte *wc);
-
-static int __dump_descriptors(struct wcdte *wc)
-{
- volatile unsigned char *writechunk, *readchunk;
- int o2, i, j;
-
- if (debug_des_cnt == 0)
- return 1;
-
- printk("Transmit Descriptors (wc->tdbl = %d)\n", wc->tdbl);
- for (i = 0; i < ERING_SIZE; i++)
- {
- writechunk = (volatile unsigned char *)(wc->writechunk);
- writechunk += i * SFRAME_SIZE;
- o2 = i * 4;
-
- if (i == wc->tdbl)
- printk("->");
- else
- printk(" ");
- if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
- printk("AN983 owns : ");
- else
- printk("Driver owns: ");
-
- for (j = 0; j < debug_des; j++)
- printk("%02X ", writechunk[j]);
- printk("\n");
- }
-
- printk("Receive Descriptors (wc->rdbl = %d)\n", wc->rdbl);
- for (i = 0; i < ERING_SIZE; i++)
- {
- readchunk = (volatile unsigned char *)wc->readchunk;
- readchunk += i * SFRAME_SIZE;
- o2 = i * 4;
- o2 += ERING_SIZE * 4;
-
- if (i == wc->rdbl)
- printk("->");
- else
- printk(" ");
- if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
- printk("AN983 owns : ");
- else
- printk("Driver owns: ");
-
- for (j = 0; j < debug_des; j++)
- printk("%02X ", readchunk[j]);
- printk("\n");
- }
- if (debug_des_cnt > 0)
- debug_des_cnt--;
- return 0;
-}
-
-/* Sanity check values */
-static inline int zt_tc_sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
-{
- if (zth->dstoffset >= sizeof(zth->dstdata))
- return 0;
- if (zth->dstlen >= sizeof(zth->dstdata))
- return 0;
- if (outbytes >= sizeof(zth->dstdata))
- return 0;
- if ((zth->dstoffset + zth->dstlen + outbytes) >= sizeof(zth->dstdata))
- return 0;
- if (zth->srcoffset >= sizeof(zth->srcdata))
- return 0;
- if (zth->srclen >= sizeof(zth->srcdata))
- return 0;
- if ((zth->srcoffset + zth->srclen) > sizeof(zth->srcdata))
- return 0;
- return 1;
-}
-
-static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc)
-{
- state_ptr->encoder = encoder;
- state_ptr->wc = wc;
- state_ptr->timestamp = 0;
- state_ptr->seqno = 0;
-
- state_ptr->cmd_seqno = 0;
-
- state_ptr->packets_sent = 0;
- state_ptr->packets_received = 0;
- state_ptr->last_dte_seqno = 0;
- state_ptr->dte_seqno_rcv = 0;
-
- state_ptr->chan_in_num = 999;
- state_ptr->chan_out_num = 999;
-
- state_ptr->ssrc = 0x78;
-
- if (encoder == 1)
- {
- state_ptr->timeslot_in_num = channel * 2;
- state_ptr->timeslot_out_num = channel * 2 + 1;
- } else {
- state_ptr->timeslot_in_num = channel * 2 + 1;
- state_ptr->timeslot_out_num = channel * 2;
- }
-}
-
-static unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt)
-{
- unsigned int pt;
-
- switch(fmt)
- {
+ switch(fmt) {
case ZT_FORMAT_G723_1:
pt = DTE_FORMAT_G723_1;
break;
@@ -553,808 +552,1700 @@
break;
default:
pt = DTE_FORMAT_UNDEF;
- }
-
- return(pt);
-}
-
-static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
-{
- outl(val, wc->iobase + addr);
-}
-
-static inline unsigned int __wcdte_getctl(struct wcdte *wc, unsigned int addr)
-{
- return inl(wc->iobase + addr);
-}
-
-static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
-{
- unsigned long flags;
- spin_lock_irqsave(&wc->reglock, flags);
- __wcdte_setctl(wc, addr, val);
- spin_unlock_irqrestore(&wc->reglock, flags);
-}
-
-static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s)
-{
- int o2 = 0;
- o2 += dbl * 4;
-
- if (!tx)
- o2 += ERING_SIZE * 4;
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
-
- wcdte_setctl(wc, 0x0008, 0x00000000);
-}
-
-static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr)
-{
- unsigned long flags;
- unsigned int val;
- spin_lock_irqsave(&wc->reglock, flags);
- val = __wcdte_getctl(wc, addr);
- spin_unlock_irqrestore(&wc->reglock, flags);
- return val;
-}
-
-static inline int __transmit_demand(struct wcdte *wc)
-{
- volatile unsigned char *writechunk;
- int o2,i,j;
- unsigned int reg, xmt_length;
-
- reg = wcdte_getctl(wc, 0x0028) & 0x00700000;
-
- /* Already transmiting, no need to demand another */
- if (!((reg == 0) || (reg = 6)))
- return(1);
-
- /* Nothing to transmit */
- if (wc->cmdq_rndx == wc->cmdq_wndx)
- return(1);
-
- /* Nothing to transmit */
- if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 )
- return(1);
-
- writechunk = (volatile unsigned char *)(wc->writechunk);
-
- writechunk += wc->tdbl * SFRAME_SIZE;
-
- o2 = wc->tdbl * 4;
-
- do
- {
- } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000));
-
- xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen;
- if (xmt_length < 64)
- xmt_length = 64;
-
- wc->descripchunk[o2+1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2+1]) & 0xFBFFF800) | xmt_length);
-
- for(i = 0; i < wc->cmdq[wc->cmdq_rndx].cmdlen; i++)
- writechunk[i] = wc->cmdq[wc->cmdq_rndx].cmd[i];
- for (j = i; j < xmt_length; j++)
- writechunk[j] = 0;
-
- if (debug_packets && (writechunk[12] == 0x88) && (writechunk[13] == 0x9B))
- {
- printk("wcdte debug: TX: ");
- for (i=0; i<debug_packets; i++)
- printk("%02X ", writechunk[i]);
- printk("\n");
- }
-
- wc->cmdq[wc->cmdq_rndx].cmdlen = 0;
-
- wc->descripchunk[o2] = cpu_to_le32(0x80000000);
- wcdte_setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */
-
- wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
-
- wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS;
-
- return(0);
-}
-
-static inline int transmit_demand(struct wcdte *wc)
-{
- int val;
- down(&wc->cmdqsem);
- val = __transmit_demand(wc);
- up(&wc->cmdqsem);
- return val;
-}
-
-static int dte_operation(struct zt_transcoder_channel *ztc, int op)
-{
- struct zt_transcoder_channel *compl_ztc;
- struct dte_state *st = ztc->pvt, *compl_st;
- struct zt_transcode_header *zth = ztc->tch;
- struct wcdte *wc = st->wc;
- unsigned char *chars;
- unsigned int inbytes = 0;
- unsigned int timestamp_inc = 0;
- int i = 0;
- int res = 0;
- unsigned int ipchksum, ndx;
- switch(op) {
- case ZT_TCOP_ALLOCATE:
+ 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 unsigned long alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ struct tcb *cmd;
+ /* const static char dev_mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; */
+ if ((cmd = __alloc_cmd(alloc_flags, 0))) {
+ int res;
+ cmd->data_len = skb->len;
+ if ((res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len))) {
+ DTE_PRINTK(WARNING,
+ "Failed call to skb_copy_bits.\n");
+ free_cmd(cmd);
+ cmd = NULL;
+ }
+ /* When we set up our interface we indicated that we do not
+ * support ARP. Therefore, the destination MAC on packets
+ * arriving from the kernel networking components are not
+ * going to be correct. Let's fix that here.
+ */
+ /* \todo let us just use whatever was in the packet already... */
+ /* memcpy(&cmd->cmd[6], dev_mac, sizeof(dev_mac)); */
+ }
+ return cmd;
+}
+
+static void
+wctc4xxp_net_set_multi(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n",
+ __FUNCTION__, netdev->promiscuity);
+}
+
+static int
+wctc4xxp_net_up(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_poll_enable(netdev);
+#else
+ napi_enable(&wc->napi);
+#endif
+#endif
+ return 0;
+}
+
+static int
+wctc4xxp_net_down(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_poll_disable(netdev);
+#else
+ napi_disable(&wc->napi);
+#endif
+#endif
+ return 0;
+}
+
+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 = netdev->priv;
+ struct tcb *cmd;
+
+ /* We set DO_NOT_CAPTURE because this packet was already captured by
+ * in code higher up in the networking stack. We don't want to
+ * capture it twice.
+ */
+ if ((cmd = wctc4xxp_skb_to_cmd(wc, skb))) {
+ cmd->flags |= DO_NOT_CAPTURE;
+ wctc4xxp_transmit_cmd(wc, cmd);
+ }
+
+ 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 = netdev->priv;
+ 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)) {
+ netif_rx_complete(wc->netdev, &wc->napi);
+ }
+ return count;
+}
+#endif
+
+static struct net_device_stats *
+wctc4xxp_net_get_stats(struct net_device *netdev)
+{
+ struct wcdte *wc = netdev->priv;
+ return &wc->net_stats;
+}
+
+/* Wait until this device is put into promiscuous mode, or we timeout. */
+static void
+wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc)
+{
+ unsigned int seconds = 15;
+ unsigned long start = jiffies;
+ struct net_device *netdev = wc->netdev;
+
+ DTE_PRINTK(INFO,
+ "Waiting %d seconds for adapter to be placed in " \
+ "promiscuous mode for early trace.\n", seconds);
+
+ while (!netdev->promiscuity) {
+ if (signal_pending(current)) {
+ DTE_PRINTK(INFO,
+ "Aborting wait due to signal.\n");
+ break;
+ }
+ msleep(100);
+ if (time_after(jiffies, start + (seconds * HZ))) {
+ DTE_PRINTK(INFO,
+ "Aborting wait due to timeout.\n");
+ break;
+ }
+ }
+}
+
+static int wctc4xxp_turn_off_booted_led(struct wcdte *wc);
+static void wctc4xxp_turn_on_booted_led(struct wcdte *wc);
+
+static int
+wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct wcdte *wc = netdev->priv;
+ switch(cmd) {
+ case 0x89f0:
down(&wc->chansem);
- if (ztc->chan_built == 0)
- {
- if (st->encoder == 1)
- wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->srcfmt), wcdte_zapfmt_to_dtefmt(zth->dstfmt),
- st->timeslot_in_num, st->timeslot_out_num, &(st->chan_in_num), &(st->chan_out_num));
- else
- wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->dstfmt), wcdte_zapfmt_to_dtefmt(zth->srcfmt),
- st->timeslot_out_num, st->timeslot_in_num, &(st->chan_out_num), &(st->chan_in_num));
- /* Mark this channel as built */
- ztc->chan_built = 1;
- ztc->built_fmts = zth->dstfmt | zth->srcfmt;
-
- /* Mark the channel complement (other half of encoder/decoder pair) as built */
- ndx = st->timeslot_in_num/2;
- if (st->encoder == 1)
- compl_ztc = &(wc->udecode->channels[ndx]);
- else
- compl_ztc = &(wc->uencode->channels[ndx]);
- compl_ztc->chan_built = 1;
- compl_ztc->built_fmts = zth->dstfmt | zth->srcfmt;
- compl_st = compl_ztc->pvt;
- compl_st->chan_in_num = st->chan_out_num;
- compl_st->chan_out_num = st->chan_in_num;
- }
+ wctc4xxp_turn_off_booted_led(wc);
+ break;
+ case 0x89f1:
+ wctc4xxp_turn_on_booted_led(wc);
up(&wc->chansem);
break;
- case ZT_TCOP_RELEASE:
- down(&wc->chansem);
- ndx = st->timeslot_in_num/2;
-
- if (st->encoder == 1)
- compl_ztc = &(wc->udecode->channels[ndx]);
- else
- compl_ztc = &(wc->uencode->channels[ndx]);
-
- /* If the channel complement (other half of the encoder/decoder pair) is not being used... */
- if ((compl_ztc->flags & ZT_TC_FLAG_BUSY) == 0)
- {
- if (st->encoder == 1)
- wcdte_destroy_channel(wc, st->chan_in_num, st->chan_out_num);
- else
- wcdte_destroy_channel(wc, st->chan_out_num, st->chan_in_num);
-
- /* Mark this channel as not built */
- ztc->chan_built = 0;
- ztc->built_fmts = 0;
- st->chan_in_num = 999;
- st->chan_out_num = 999;
-
- /* Mark the channel complement as not built */
- compl_ztc->chan_built = 0;
- compl_ztc->built_fmts = 0;
- compl_st = compl_ztc->pvt;
- compl_st->chan_in_num = 999;
- compl_st->chan_out_num = 999;
+ default:
+ return -EOPNOTSUPP;
+ };
+ return 0;
+}
+
+/**
+ * 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;
+ const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+
+ if (!(netdev = alloc_netdev(0, wc->board_name, ether_setup))) {
+ return -ENOMEM;
+ }
+
+ memcpy(netdev->dev_addr, our_mac, sizeof(our_mac));
+ netdev->priv = wc;
+ netdev->set_multicast_list = &wctc4xxp_net_set_multi;
+ netdev->open = &wctc4xxp_net_up;
+ netdev->stop = &wctc4xxp_net_down;
+ netdev->hard_start_xmit = &wctc4xxp_net_hard_start_xmit;
+ netdev->get_stats = &wctc4xxp_net_get_stats;
+ netdev->do_ioctl = &wctc4xxp_net_ioctl;
+ netdev->promiscuity = 0;
+ netdev->flags |= IFF_NOARP;
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netdev->poll = &wctc4xxp_poll;
+ netdev->weight = 64;
+# else
+ netif_napi_add(netdev, &wc->napi, &wctc4xxp_poll, 64);
+# endif
+
+ if ((res = register_netdev(netdev))) {
+ DTE_PRINTK(WARNING,
+ "Failed to register network device %s.\n",
+ wc->board_name);
+ goto error_sw;
+ }
+
+ wc->netdev = netdev;
+ skb_queue_head_init(&wc->captured_packets);
+
+ if (debug & DTE_DEBUG_NETWORK_EARLY) {
+ wctc4xxp_net_waitfor_promiscuous(wc);
+ }
+
+ DTE_PRINTK(DEBUG,
+ "Created network device %s for debug.\n", wc->board_name);
+ return 0;
+
+error_sw:
+ if (netdev) free_netdev(netdev);
+ return res;
+}
+
+static void
+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;
+ }
+
+ if (!(skb = tcb_to_skb(netdev, cmd))) {
+ return;
+ }
+
+ skb_queue_tail(&wc->captured_packets, skb);
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ netif_rx_schedule(netdev);
+# else
+ netif_rx_schedule(netdev, &wc->napi);
+# endif
+ return;
+}
+
+
+/*! In-memory structure shared by the host and the adapter. */
+struct wctc4xxp_descriptor {
+ __le32 des0;
+ __le32 des1;
+ __le32 buffer1;
+ __le32 container; /* Unused */
+} __attribute__((packed));
+
+#define DRING_SIZE (1 << 3) /* Must be a power of two */
+#define DRING_MASK (DRING_SIZE-1)
+#define MIN_PACKET_LEN 64
+
+struct wctc4xxp_descriptor_ring {
+ /* Pointer to an array of descriptors to give to hardware. */
+ struct wctc4xxp_descriptor* desc;
+ /* Read completed buffers from the head. */
+ unsigned int head;
+ /* Write ready buffers to the tail. */
+ unsigned int tail;
+ /* Array to save the kernel virtual address of pending commands. */
+ struct tcb *pending[DRING_SIZE];
+ /* PCI Bus address of the descriptor list. */
+ dma_addr_t desc_dma;
+ /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
+ unsigned int direction;
+ /*! The number of buffers currently submitted to the hardware. */
+ unsigned int count;
+ /*! The number of bytes to pad each descriptor for cache alignment. */
+ unsigned int padding;
+ /*! Protects this structure from concurrent access. */
+ spinlock_t lock;
+ /*! PCI device for the card associated with this ring. */
+ struct pci_dev *pdev;
+};
+
+/**
+ * wctc4xxp_descriptor - Returns the desriptor at index.
+ * @dr: The descriptor ring we're using.
+ * @index: index of the descriptor we want.
+ *
+ * We need this function because we do not know what the padding on the
+ * descriptors will be. Otherwise, we would just use an array.
+ */
+static inline struct wctc4xxp_descriptor *
+wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index)
+{
+ return (struct wctc4xxp_descriptor *)((u8*)dr->desc +
+ ((sizeof(*dr->desc) + dr->padding) * index));
+}
+
+static int
+wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descriptor_ring *dr,
+ u32 des1, unsigned int direction)
+{
+ int i;
+ const u32 END_OF_RING = 0x02000000;
+ u8 cache_line_size = 0;
+ struct wctc4xxp_descriptor *d;
+
+ BUG_ON(!pdev);
+ BUG_ON(!dr);
+
+ if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) {
+ /* \todo Print an error message... */
+ return -EIO;
+ }
+
+ memset(dr, 0, sizeof(*dr));
+
+ /*
+ * Add some padding to each descriptor to ensure that they are
+ * aligned on host system cache-line boundaries, but only for the
+ * cache-line sizes that we support.
[... 4538 lines stripped ...]
More information about the zaptel-commits
mailing list