From c990a6d6901cc88a727578ab95a85280ec9a710d Mon Sep 17 00:00:00 2001 From: kpfleming Date: Thu, 14 Aug 2008 01:57:01 +0000 Subject: backport new transcoder interface and driver from DAHDI git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4483 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/wctc4xxp/Kbuild | 2 +- kernel/wctc4xxp/Makefile | 10 - kernel/wctc4xxp/base.c | 4166 +++++++++++++++++++++++++++--------------- kernel/wctc4xxp/codec_test.c | 329 ---- kernel/zaptel-base.c | 50 +- kernel/zaptel.h | 146 +- kernel/zttranscode.c | 564 +++--- 7 files changed, 3090 insertions(+), 2177 deletions(-) delete mode 100644 kernel/wctc4xxp/codec_test.c diff --git a/kernel/wctc4xxp/Kbuild b/kernel/wctc4xxp/Kbuild index 353290f..5783b14 100644 --- a/kernel/wctc4xxp/Kbuild +++ b/kernel/wctc4xxp/Kbuild @@ -8,7 +8,7 @@ ifeq ($(HOTPLUG_FIRMWARE),yes) EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE endif -wctc4xxp-objs := base.o +wctc4xxp-objs := base.o ifneq ($(HOTPLUG_FIRMWARE),yes) wctc4xxp-objs += $(FIRM_DIR)/zaptel-fw-tc400m.o diff --git a/kernel/wctc4xxp/Makefile b/kernel/wctc4xxp/Makefile index 725abc4..56453cb 100644 --- a/kernel/wctc4xxp/Makefile +++ b/kernel/wctc4xxp/Makefile @@ -3,14 +3,4 @@ ifneq ($(KBUILD_EXTMOD),) # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild - -else - -tests: codec_test - -codec_test: codec_test.c ../zaptel.h - $(CC) -o $@ $< $(CFLAGS) - -clean: - rm -rf codec_test endif diff --git a/kernel/wctc4xxp/base.c b/kernel/wctc4xxp/base.c index 90642b8..2cf24d7 100644 --- a/kernel/wctc4xxp/base.c +++ b/kernel/wctc4xxp/base.c @@ -1,9 +1,7 @@ /* * Wildcard TC400B Driver * - * Written by John Sloan - * - * Copyright (C) 2006, Digium, Inc. + * Copyright (C) 2006-2008, Digium, Inc. * * All rights reserved. * @@ -26,86 +24,154 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include -#include #include -#include #include #include -#ifdef CONFIG_DEVFS_FS -#include -#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 */ +#include +#include +#include +#include +#include -#define ACK_SPACE 20 - -#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE) -#define MAX_RCV_COMMANDS 16 - -/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */ -#define BOOT_CMD_LEN 1500 -#define OTHER_CMD_LEN 300 - -#define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */ +#include "zaptel.h" -#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */ +/* COMPILE TIME OPTIONS =================================================== */ -#define SFRAME_SIZE MAX_COMMAND_LEN +#define INTERRUPT 0 +#define WORKQUEUE 1 +#define TASKLET 2 -#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4)) +#ifndef DEFERRED_PROCESSING +# define DEFERRED_PROCESSING WORKQUEUE +#endif -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 +#if DEFERRED_PROCESSING == INTERRUPT +# define ALLOC_FLAGS GFP_ATOMIC +#elif DEFERRED_PROCESSING == TASKLET +# define ALLOC_FLAGS GFP_ATOMIC +#else +# define ALLOC_FLAGS GFP_KERNEL +#endif -#define RCV_CSMENCAPS 1 -#define RCV_RTP 2 -#define RCV_CSMENCAPS_ACK 3 -#define RCV_OTHER 99 +#define WARN() WARN_ON(1) + +#define DTE_PRINTK(_lvl, _fmt, _args...) \ + printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \ + (wc)->board_name, ## _args) + +#define DTE_DEBUG(_dbgmask, _fmt, _args...) \ + if ((debug & _dbgmask) == (_dbgmask)) { \ + printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \ + (wc)->board_name, ## _args); \ + } \ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#define WARN_ON_ONCE(__condition) do { \ + static int __once = 1; \ + if (unlikely(__condition)) { \ + if (__once) { \ + __once = 0; \ + WARN_ON(0); \ + } \ + } \ +} while(0) +#endif +#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */ +#define MAX_CHANNEL_PACKETS 5 /* Never let more than 5 outstanding packets exist for any channel. */ + +#define G729_LENGTH 20 +#define G723_LENGTH 30 + +#define G729_SAMPLES 160 /* G.729 */ +#define G723_SAMPLES 240 /* G.723.1 */ + +#define G729_BYTES 20 /* G.729 */ +#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */ +#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */ +#define G723_SID_BYTES 4 /* G.723.1 SID frame */ + +#define MAX_CAPTURED_PACKETS 5000 + +/* The following bit fields are used to set the various debug levels. */ +#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */ +#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */ +#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */ +#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */ +#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */ +#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */ +#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */ + +int debug; +char *mode; + +static spinlock_t wctc4xxp_list_lock; +static struct list_head wctc4xxp_list; + +#define ETH_P_CSM_ENCAPS 0x889B + +struct rtphdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 csrc_count:4; + __u8 extension:1; + __u8 padding:1; + __u8 ver:2; + __u8 type:7; + __u8 marker:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 ver:2; + __u8 padding:1; + __u8 extension:1; + __u8 csrc_count:4; + __u8 marker:1; + __u8 type:7; +#else +#error "Please fix " +#endif + __be16 seqno; + __be32 timestamp; + __be32 ssrc; +} __attribute__((packed)); + +struct rtp_packet { + struct ethhdr ethhdr; + struct iphdr iphdr; + struct udphdr udphdr; + struct rtphdr rtphdr; + __u8 payload[0]; +}__attribute__((packed)); + +/* Ethernet packet type for communication control information to the DTE. */ +struct csm_encaps_hdr { + struct ethhdr ethhdr; + /* CSM_ENCAPS HEADER */ + __be16 op_code; + __u8 seq_num; + __u8 control; + __be16 channel; + /* COMMON PART OF PAYLOAD HEADER */ + __u8 length; + __u8 index; + __u8 type; + __u8 class; + __le16 function; + __le16 reserved; + __le16 params[0]; +} __attribute__((packed)); + +struct csm_create_channel_cmd { + struct csm_encaps_hdr hdr; + __le16 channel_type; + __le16 timeslot; +} __attribute__((packed)); -/* TDM Commands */ #define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30 #define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ @@ -181,17 +247,26 @@ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \ 0x02,0x00 } -/* Supervisor channel commands */ -#define CMD_MSG_CREATE_CHANNEL_LEN 32 -#define CMD_MSG_CREATE_CHANNEL(s,t) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \ - 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) } +#define CONTROL_PACKET_OPCODE 0x0001 +/* Control bits */ +#define LITTLE_ENDIAN 0x01 +#define SUPPRESS_ACK 0x40 +#define MESSAGE_PACKET 0x80 + +#define SUPERVISOR_CHANNEL 0xffff + +/* Supervisor function codes */ +#define SUPVSR_CREATE_CHANNEL 0x0010 + +#define CONFIG_CHANGE_TYPE 0x00 +#define CONFIG_DEVICE_CLASS 0x06 + #define CMD_MSG_QUERY_CHANNEL_LEN 30 #define CMD_MSG_QUERY_CHANNEL(s,t) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \ (t&0x00FF), ((t&0xFF00) >> 8) } + #define CMD_MSG_TRANS_CONNECT_LEN 38 #define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ @@ -242,154 +317,104 @@ 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; }; -struct wcdte { - struct pci_dev *dev; - char *variety; - unsigned int intcount; - unsigned int rxints; - unsigned int txints; - unsigned int intmask; - int pos; - int freeregion; - int rdbl; - int tdbl; - int cards; - spinlock_t reglock; - wait_queue_head_t regq; - int rcvflags; - - struct semaphore chansem; - struct semaphore cmdqsem; - struct cmdq cmdq[MAX_COMMANDS]; - unsigned int cmdq_wndx; - unsigned int cmdq_rndx; - - unsigned int last_seqno; - unsigned int last_rseqno; - unsigned int last_command_sent; - unsigned int last_rcommand; - unsigned int last_rparm1; - unsigned int seq_num; - long timeout; - - unsigned int dsp_crashed; - unsigned int dumping; +static inline void *hdr_from_cmd(struct tcb *cmd) { + return cmd->data; +} - unsigned int ztsnd_rtx; - unsigned int ztsnd_0010_rtx; +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; +} - unsigned char numchannels; - unsigned char complexname[40]; +#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 - unsigned long iobase; - dma_addr_t readdma; - dma_addr_t writedma; - dma_addr_t descripdma; - volatile unsigned int *writechunk; /* Double-word aligned write memory */ - volatile unsigned int *readchunk; /* Double-word aligned read memory */ - volatile unsigned int *descripchunk; /* Descriptors */ - - int wqueints; - struct workqueue_struct *dte_wq; - struct work_struct dte_work; +static inline struct tcb * +__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags) +{ + struct tcb *cmd; - struct zt_transcoder *uencode; - struct zt_transcoder *udecode; -}; + cmd = kmem_cache_alloc(cmd_cache, alloc_flags); + if (likely(cmd)) { + initialize_cmd(cmd, cmd_flags); + } + return cmd; +} -struct wcdte_desc { - char *name; - int flags; -}; +static struct tcb * +alloc_cmd(void) +{ + return __alloc_cmd(GFP_KERNEL, 0); +} -static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 }; -static struct wcdte_desc wctce400 = { "Wildcard TCE400+TC400M", 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 struct wcdte *ifaces[WC_MAX_IFACES]; +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; +}; -/* - * 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 channel_pvt { + spinlock_t lock; /* Lock for this structure */ + encode_t encoder; /* If we're an encoder */ struct wcdte *wc; unsigned int timestamp; @@ -397,148 +422,122 @@ struct dte_state { 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 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 chennel on which results we be received from */ - unsigned int chan_out_num; /* DTE channel to send data to */ + unsigned int chan_in_num; /* DTE channel on which results will be received from */ + unsigned int chan_out_num; /* DTE channel to send data to */ - unsigned int packets_sent; - unsigned int packets_received; + struct channel_stats stats; - unsigned int last_dte_seqno; - unsigned int dte_seqno_rcv; + u16 last_dte_seqno; + unsigned int wctc4xxp_seqno_rcv; unsigned char ssrc; + struct list_head rx_queue; /* Transcoded packets for this channel. */ }; +struct wcdte { + char board_name[40]; + const char *variety; + int pos; + int cards; + struct list_head node; + spinlock_t reglock; + wait_queue_head_t waitq; + struct semaphore chansem; +#define DTE_READY 1 +#define DTE_SHUTDOWN 2 + unsigned long flags; -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; + 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; - if (debug_des_cnt == 0) - return 1; + unsigned int seq_num; + unsigned char numchannels; + unsigned char complexname[40]; - 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; -} + /* 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 zt_transcoder *uencode; + struct zt_transcoder *udecode; + struct channel_pvt *encoders; + struct channel_pvt *decoders; -/* 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; -} +#if DEFERRED_PROCESSING == WORKQUEUE + struct work_struct deferred_work; +#endif -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; + /* + * 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; - 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; +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); +} - state_ptr->chan_in_num = 999; - state_ptr->chan_out_num = 999; +#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 - 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; - } -} +#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 unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt) +static inline u8 wctc4xxp_zapfmt_to_dtefmt(unsigned int fmt) { - unsigned int pt; + u8 pt; - switch(fmt) - { + switch(fmt) { case ZT_FORMAT_G723_1: pt = DTE_FORMAT_G723_1; break; @@ -553,808 +552,1700 @@ static unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt) break; default: pt = DTE_FORMAT_UNDEF; + break; } - return(pt); + 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) +static struct sk_buff * +tcb_to_skb(struct net_device *netdev, const struct tcb *cmd) { - return inl(wc->iobase + addr); + 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; } -static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) +/** + * 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) { - unsigned long flags; - spin_lock_irqsave(&wc->reglock, flags); - __wcdte_setctl(wc, addr, val); - spin_unlock_irqrestore(&wc->reglock, flags); + 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 inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s) +static void +wctc4xxp_net_set_multi(struct net_device *netdev) { - int o2 = 0; - o2 += dbl * 4; - - if (!tx) - o2 += ERING_SIZE * 4; - wc->descripchunk[o2] = cpu_to_le32(0x80000000); - - wcdte_setctl(wc, 0x0008, 0x00000000); + struct wcdte *wc = netdev->priv; + DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n", + __FUNCTION__, netdev->promiscuity); } -static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr) +static int +wctc4xxp_net_up(struct net_device *netdev) { - 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; + 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 inline int __transmit_demand(struct wcdte *wc) +static int +wctc4xxp_net_down(struct net_device *netdev) { - volatile unsigned char *writechunk; - int o2,i,j; - unsigned int reg, xmt_length; + 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; +} - reg = wcdte_getctl(wc, 0x0028) & 0x00700000; - - /* Already transmiting, no need to demand another */ - if (!((reg == 0) || (reg = 6))) - return(1); +static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *); - /* Nothing to transmit */ - if (wc->cmdq_rndx == wc->cmdq_wndx) - return(1); +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); + } - /* Nothing to transmit */ - if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 ) - return(1); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} - writechunk = (volatile unsigned char *)(wc->writechunk); +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; +} - writechunk += wc->tdbl * SFRAME_SIZE; +#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); - o2 = wc->tdbl * 4; + count = wctc4xxp_net_receive(wc, quota); - do - { - } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)); + *budget -= count; + netdev->quota -= count; - 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; icaptured_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; - 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; + count = wctc4xxp_net_receive(wc, budget); - wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS; + if (!skb_queue_len(&wc->captured_packets)) { + netif_rx_complete(wc->netdev, &wc->napi); + } + return count; +} +#endif - return(0); +static struct net_device_stats * +wctc4xxp_net_get_stats(struct net_device *netdev) +{ + struct wcdte *wc = netdev->priv; + return &wc->net_stats; } -static inline int transmit_demand(struct wcdte *wc) +/* Wait until this device is put into promiscuous mode, or we timeout. */ +static void +wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc) { - int val; - down(&wc->cmdqsem); - val = __transmit_demand(wc); - up(&wc->cmdqsem); - return val; + 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 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: +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; - } - up(&wc->chansem); + wctc4xxp_turn_off_booted_led(wc); 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; - } - st->dte_seqno_rcv = 0; + case 0x89f1: + wctc4xxp_turn_on_booted_led(wc); up(&wc->chansem); break; - case ZT_TCOP_TRANSCODE: - if ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) ) - || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES)) - || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) ) - { - do - { - chars = (unsigned char *)(zth->srcdata + zth->srcoffset); - - if ((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) { - if (zth->dstfmt == ZT_FORMAT_G729A) { - inbytes = G729_SAMPLES; - timestamp_inc = G729_SAMPLES; - } else if (zth->dstfmt == ZT_FORMAT_G723_1) { - inbytes = G723_SAMPLES; - timestamp_inc = G723_SAMPLES; - } - } else if (zth->srcfmt == ZT_FORMAT_G729A) { - inbytes = G729_BYTES; - timestamp_inc = G729_SAMPLES; - } else if (zth->srcfmt == ZT_FORMAT_G723_1) { - /* determine the size of the frame */ - switch (chars[0] & 0x03) { - case 0x00: - inbytes = G723_6K_BYTES; - break; - case 0x01: - inbytes = G723_5K_BYTES; - break; - case 0x02: - inbytes = G723_SID_BYTES; - break; - case 0x03: - /* this is a 'reserved' value in the G.723.1 - spec and should never occur in real media streams */ - inbytes = G723_SID_BYTES; - break; - } - timestamp_inc = G723_SAMPLES; - } - - zth->srclen -= inbytes; - - { - unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_IP_UDP_RTP( - ((inbytes+40) >> 8) & 0xFF, - (inbytes+40) & 0xFF, - st->seqno & 0xFF, - 0x00, - 0x00, - (((st->timeslot_out_num) >> 8)+0x50) & 0xFF, - (st->timeslot_out_num) & 0xFF, - (((st->timeslot_in_num) >> 8)+0x50) & 0xFF, - (st->timeslot_in_num) & 0xFF, - ((inbytes+20) >> 8) & 0xFF, - (inbytes+20) & 0xFF, - 0x00, - 0x00, - wcdte_zapfmt_to_dtefmt(zth->srcfmt), - ((st->seqno) >> 8) & 0xFF, - (st->seqno) & 0xFF, - ((st->timestamp) >> 24) & 0xFF, - ((st->timestamp) >> 16) & 0xFF, - ((st->timestamp) >> 8) & 0xFF, - (st->timestamp) & 0xFF, - (st->ssrc) & 0xFF); - - ipchksum = 0x9869 + (fifo[16] << 8) + fifo[17] - + (fifo[18] << 8) + fifo[19]; - while (ipchksum >> 16) - ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16); - ipchksum = (~ipchksum) & 0xFFFF; - - fifo[24] = ipchksum >> 8; - fifo[25] = ipchksum & 0xFF; - - st->seqno += 1; - st->timestamp += timestamp_inc; - - for (i = 0; i < inbytes; i++) - fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i]; - - down(&wc->cmdqsem); - - if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) - printk("wcdte error: cmdq is full.\n"); - else - { - wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_IP_UDP_RTP_LEN+inbytes; - for (i = 0; i < CMD_MSG_IP_UDP_RTP_LEN+inbytes; i++) - wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; - wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; - } - - __transmit_demand(wc); - up(&wc->cmdqsem); - } - st->packets_sent++; + 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; + } - zth->srcoffset += inbytes; + 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); - } while ((((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) ) - || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES)) - || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) ); + if (debug & DTE_DEBUG_NETWORK_EARLY) { + wctc4xxp_net_waitfor_promiscuous(wc); + } - } else { - zt_transcoder_alert(ztc); - } + DTE_PRINTK(DEBUG, + "Created network device %s for debug.\n", wc->board_name); + return 0; - res = 0; - break; - } +error_sw: + if (netdev) free_netdev(netdev); return res; } -static void wcdte_stop_dma(struct wcdte *wc); - -static inline void wcdte_receiveprep(struct wcdte *wc, int dbl) +static void +wctc4xxp_net_unregister(struct wcdte *wc) { - volatile unsigned char *readchunk; - struct zt_transcoder_channel *ztc = NULL; - struct zt_transcode_header *zth = NULL; - struct dte_state *st = NULL; - int o2,i; - unsigned char rseq, rcodec; - unsigned int rcommand, rchannel, rlen, rtp_rseq, rtp_eseq; - unsigned char *chars = NULL; - unsigned int ztc_ndx; + struct sk_buff *skb; + if (!wc->netdev) { + return; + } - readchunk = (volatile unsigned char *)wc->readchunk; - readchunk += dbl * SFRAME_SIZE; + unregister_netdev(wc->netdev); - o2 = dbl * 4; - o2 += ERING_SIZE * 4; + while ((skb = skb_dequeue(&wc->captured_packets))) { + kfree_skb(skb); + } - /* Control in packet */ - if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B)) - { - if (debug_packets) - { - printk("wcdte debug: RX: "); - for (i=0; icmdqsem); - if ((readchunk[17] & 0x40) == 0) { - if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) - printk("wcdte error: cmdq is full (rndx = %d, wndx = %d).\n", wc->cmdq_rndx, wc->cmdq_wndx); - else - { - unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_ACK(rseq++, rchannel); - - wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_ACK_LEN; - for (i = 0; i < wc->cmdq[wc->cmdq_wndx].cmdlen; i++) - wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; - wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; - } + free_netdev(wc->netdev); + wc->netdev = NULL; +} - __transmit_demand(wc); - } - - wc->rcvflags = RCV_CSMENCAPS; - if (rcommand == wc->last_command_sent) { - wc->last_rcommand = rcommand; - wc->last_rparm1 = readchunk[28] | (readchunk[29] << 8); - wake_up(&wc->regq); - } else { - if (debug) - printk("wcdte error: unexpected command response received (sent: %04X, received: %04X)\n", wc->last_command_sent, rcommand); - } - up(&wc->cmdqsem); - } - else - { - wc->last_rseqno = readchunk[16]; - wc->rcvflags = RCV_CSMENCAPS_ACK; - if (!wc->dumping) - wake_up_interruptible(&wc->regq); - else - wake_up(&wc->regq); - } - if ((readchunk[22] == 0x75) && (readchunk[23] = 0xC1)) - { - if (debug) - printk("wcdte error: received alert (0x%02X%02X) from dsp\n", readchunk[29], readchunk[28]); - if (debug_des) { - down(&wc->cmdqsem); - __dump_descriptors(wc); - up(&wc->cmdqsem); - } - } +/** + * 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 (wc->dumping && (readchunk[22] == 0x04) && (readchunk[23] = 0x14)) { - for (i = 27; i < 227; i++) - printk("%02X ", readchunk[i]); - printk("\n"); - } + if (!netdev) { + return; } - /* IP/UDP in packet */ - else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00) - && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78)) - { - rchannel = (readchunk[37] | (readchunk[36] << 8)) - 0x5000; - rlen = (readchunk[39] | (readchunk[38] << 8)) - 20; - rtp_rseq = (readchunk[45] | (readchunk[44] << 8)); - rcodec = readchunk[43]; - - ztc_ndx = rchannel/2; - - if (ztc_ndx >= wc->numchannels) - { - if (debug) - printk("wcdte error: Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, wc->numchannels); - rcodec = DTE_FORMAT_UNDEF; - } + /* 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 ((rcodec == 0x00) || (rcodec == 0x08)) /* ulaw or alaw (decoders) */ - { - ztc = &(wc->udecode->channels[ztc_ndx]); - zth = ztc->tch; - st = ztc->pvt; - - if (zth == NULL) - { - if (debug) - printk("wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built); - if (debug_des) { - down(&wc->cmdqsem); - __dump_descriptors(wc); - up(&wc->cmdqsem); - } - rcodec = DTE_FORMAT_UNDEF; - } else { - chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen); - st->packets_received++; - } + if (!(skb = tcb_to_skb(netdev, cmd))) { + return; + } - } - - if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */ - { - ztc = &(wc->uencode->channels[ztc_ndx]); - zth = ztc->tch; - st = ztc->pvt; - - if (zth == NULL) - { - if (debug) - printk("wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built); - if (debug_des) { - down(&wc->cmdqsem); - __dump_descriptors(wc); - up(&wc->cmdqsem); - } - rcodec = DTE_FORMAT_UNDEF; - } else { - chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen); - st->packets_received++; - } + 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; +} - } - if (st->dte_seqno_rcv == 0) - { - st->dte_seqno_rcv = 1; - st->last_dte_seqno = rtp_rseq; - } else { - rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF; - if ( (rtp_rseq != rtp_eseq) && debug ) - printk("wcdte error: Bad seqno from DTE! [%04X][%d][%d][%d]\n", (readchunk[37] | (readchunk[36] << 8)), rchannel, rtp_rseq, st->last_dte_seqno); +/*! 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; +}; - st->last_dte_seqno = rtp_rseq; - } +/** + * 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)); +} - if (rcodec == 0x00) /* ulaw */ - { - if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) { - for (i = 0; i < rlen; i++) - chars[i] = readchunk[i+54]; +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; - zth->dstlen += rlen; - zth->dstsamples = zth->dstlen; + BUG_ON(!pdev); + BUG_ON(!dr); - } else { - ztc->errorstatus = -EOVERFLOW; - } - zt_transcoder_alert(ztc); - } - else if (rcodec == 0x08) /* alaw */ - { - if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) { + if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) { + /* \todo Print an error message... */ + return -EIO; + } - for (i = 0; i < rlen; i++) - chars[i] = readchunk[i+54]; + memset(dr, 0, sizeof(*dr)); - zth->dstlen += rlen; - zth->dstsamples = zth->dstlen; + /* + * Add some padding to each descriptor to ensure that they are + * aligned on host system cache-line boundaries, but only for the + * cache-line sizes that we support. + * + */ + if ((0x08 == cache_line_size) || (0x10 == cache_line_size) || + (0x20 == cache_line_size)) + { + dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d); + } - } else { - ztc->errorstatus = -EOVERFLOW; - } - zt_transcoder_alert(ztc); - } - else if (rcodec == 0x04) /* G.723.1 */ - { - if (zt_tc_sanitycheck(zth, rlen) && - ((rlen == G723_6K_BYTES) || (rlen == G723_5K_BYTES) || (rlen == G723_SID_BYTES))) - { - for (i = 0; i < rlen; i++) - chars[i] = readchunk[i+54]; + dr->desc = pci_alloc_consistent(pdev, + (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma); - zth->dstlen += rlen; - zth->dstsamples += G723_SAMPLES; + if (!dr->desc) { + return -ENOMEM; + } - } else { - ztc->errorstatus = -EOVERFLOW; - } + 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); + } - if (!(zth->dstsamples % G723_SAMPLES)) - { - zt_transcoder_alert(ztc); - } + d->des1 |= cpu_to_le32(END_OF_RING); + dr->direction = direction; + spin_lock_init(&dr->lock); + return 0; +} + +#define OWN_BIT cpu_to_le32(0x80000000) +#define OWNED(_d_) (((_d_)->des0)&OWN_BIT) +#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb();} while (0) + +const unsigned int BUFFER1_SIZE_MASK = 0x7ff; + +static int +wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c) +{ + volatile struct wctc4xxp_descriptor *d; + unsigned int len; + + WARN_ON(!c); + len = (c->data_len < MIN_PACKET_LEN) ? MIN_PACKET_LEN : c->data_len; + if (c->data_len > 1518) { + WARN_ON_ONCE(!"Invalid command length passed\n"); + c->data_len = 1518; + } + + spin_lock_bh(&dr->lock); + d = wctc4xxp_descriptor(dr, dr->tail); + WARN_ON(!d); + if (d->buffer1) { + spin_unlock_bh(&dr->lock); + /* Do not overwrite a buffer that is still in progress. */ + return -EBUSY; + } + d->des1 &= cpu_to_le32(~(BUFFER1_SIZE_MASK)); + d->des1 |= cpu_to_le32(len & BUFFER1_SIZE_MASK); + d->buffer1 = pci_map_single(dr->pdev, c->data, + SFRAME_SIZE, dr->direction); + + SET_OWNED(d); /* That's it until the hardware is done with it. */ + dr->pending[dr->tail] = c; + dr->tail = ++dr->tail & DRING_MASK; + ++dr->count; + spin_unlock_bh(&dr->lock); + return 0; +} + +static inline struct tcb* +wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr) +{ + volatile struct wctc4xxp_descriptor *d; + struct tcb *c; + unsigned int head = dr->head; + spin_lock_bh(&dr->lock); + d = wctc4xxp_descriptor(dr, head); + if (d->buffer1 && !OWNED(d)) { + pci_unmap_single(dr->pdev, d->buffer1, + SFRAME_SIZE, dr->direction); + c = dr->pending[head]; + WARN_ON(!c); + dr->head = (++head) & DRING_MASK; + d->buffer1 = 0; + --dr->count; + WARN_ON(!c); + c->data_len = (d->des0 >> 16) & BUFFER1_SIZE_MASK; + c->flags |= TX_COMPLETE; + } else { + c = NULL; + } + spin_unlock_bh(&dr->lock); + return c; +} + +static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr) +{ + int count; + spin_lock_bh(&dr->lock); + count = dr->count; + spin_unlock_bh(&dr->lock); + return count; +} + +static inline void +__wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) +{ + outl(val, wc->iobase + addr); +} + +static inline unsigned int +__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) +{ + spin_lock_bh(&wc->reglock); + __wctc4xxp_setctl(wc, addr, val); + spin_unlock_bh(&wc->reglock); +} + +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) +{ + __wctc4xxp_setctl(wc, 0x0008, 0x00000000); + + /* \todo Investigate why this register needs to be written twice in + * order to get it to poll reliably. So far, most of the problems + * I've seen with timeouts had more to do with an untransmitted + * packet sitting in the outbound descriptor list as opposed to any + * problem with the dte firmware. + */ + __wctc4xxp_setctl(wc, 0x0008, 0x00000000); +} + +/* Returns the size, in bytes, of a CSM_ENCAPS packet, given the number of + * parameters used. */ +#define SIZE_WITH_N_PARAMETERS(__n) (sizeof(struct csm_encaps_hdr) + ((__n) * (sizeof(u16)))) + +/* There are 20 bytes in the ethernet header and the common CSM_ENCAPS header + * that we don't want in the length of the actual CSM_ENCAPS command */ +#define LENGTH_WITH_N_PARAMETERS(__n) (SIZE_WITH_N_PARAMETERS(__n) - 20) + +static const u8 dst_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; +static const u8 src_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + +static void +setup_common_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) +{ + memcpy(hdr->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); + memcpy(hdr->ethhdr.h_source, src_mac, sizeof(src_mac)); + hdr->ethhdr.h_proto = cpu_to_be16(ETH_P_CSM_ENCAPS); +} + +static 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 +__wctc4xxp_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot) +{ + struct csm_create_channel_cmd *c; + c = hdr_from_cmd(cmd); + + BUG_ON(timeslot > 0x01ff); + + setup_supervisor_header(wc, &c->hdr); + + c->hdr.length = LENGTH_WITH_N_PARAMETERS(2); + c->hdr.index = 0x0; + c->hdr.type = CONFIG_CHANGE_TYPE; + c->hdr.class = CONFIG_DEVICE_CLASS; + c->hdr.function = cpu_to_le16(SUPVSR_CREATE_CHANNEL); + c->hdr.reserved = 0x0000; + + c->channel_type = cpu_to_le16(0x0002); /* Channel type is VoIP */ + c->timeslot = cpu_to_le16(timeslot); + + cmd->flags |= WAIT_FOR_RESPONSE; + cmd->data_len = sizeof(*c); +} + +struct tcb * +wctc4xxp_create_channel_cmd(struct wcdte *wc, u16 timeslot) +{ + struct tcb *cmd; + if (!(cmd = alloc_cmd())) { + return NULL; + } + __wctc4xxp_create_channel_cmd(wc, cmd, timeslot); + return cmd; +} + +void +__wctc4xxp_create_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd) +{ + struct csm_encaps_hdr *hdr = cmd->data; + BUG_ON(SIZE_WITH_N_PARAMETERS(2) > cmd->data_len); + + setup_supervisor_header(wc, hdr); + + hdr->length = LENGTH_WITH_N_PARAMETERS(2); + hdr->index = 0x0; + hdr->type = CONFIG_CHANGE_TYPE; + hdr->class = CONFIG_DEVICE_CLASS; + hdr->function = cpu_to_le16(0x0411); + hdr->reserved = 0x0000; + hdr->params[0] = cpu_to_le16(0x012c); + hdr->params[1] = cpu_to_le16(0x0000); + + cmd->flags |= WAIT_FOR_RESPONSE; + cmd->data_len = SIZE_WITH_N_PARAMETERS(2); + return; +} + +struct tcb * +wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct zt_transcoder_channel *dtc, size_t inbytes) +{ + const struct channel_pvt *cpvt = dtc->pvt; + struct rtp_packet *packet; + struct tcb *cmd; + + if (!(cmd = alloc_cmd())) { + return NULL; + } + + 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 = cpu_to_be16(cpvt->seqno); + packet->iphdr.frag_off= cpu_to_be16(0x4000); + packet->iphdr.ttl = 64; + packet->iphdr.protocol= 0x11; /* UDP */ + packet->iphdr.check = 0; + packet->iphdr.saddr = cpu_to_be32(0xc0a80903); + packet->iphdr.daddr = cpu_to_be32(0xc0a80903); + packet->iphdr.check = ip_fast_csum((void*)&packet->iphdr, sizeof(struct iphdr)); + + /* setup the UDP header */ + packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000); + packet->udphdr.dest = cpu_to_be16(cpvt->timeslot_in_num + 0x5000); + packet->udphdr.len = cpu_to_be16(inbytes + sizeof(struct rtphdr) + sizeof(struct udphdr)); + packet->udphdr.check = 0; + + /* Setup the RTP header */ + packet->rtphdr.ver = 2; + packet->rtphdr.padding = 0; + packet->rtphdr.extension = 0; + packet->rtphdr.csrc_count = 0; + packet->rtphdr.marker = 0; + packet->rtphdr.type = wctc4xxp_zapfmt_to_dtefmt(dtc->srcfmt); + packet->rtphdr.seqno = cpu_to_be16(cpvt->seqno); + packet->rtphdr.timestamp = cpu_to_be32(cpvt->timestamp); + packet->rtphdr.ssrc = cpu_to_be32(cpvt->ssrc); + + cmd->data_len = sizeof(*packet) + inbytes; + + return cmd; +} +static void +wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr) +{ + int i; + struct wctc4xxp_descriptor *d; + + /* NOTE: The DTE must be in the stopped state. */ + spin_lock_bh(&dr->lock); + for (i = 0; i < DRING_SIZE; ++i) { + d = wctc4xxp_descriptor(dr, i); + if (d->buffer1) { + dma_unmap_single(&dr->pdev->dev, d->buffer1, + SFRAME_SIZE, dr->direction); + d->buffer1 = 0; + /* Commands will also be sitting on the waiting for + * response list, so we want to make sure to delete + * them from that list as well. */ + list_del_init(&(dr->pending[i])->node); + free_cmd(dr->pending[i]); + dr->pending[i] = NULL; } - else if (rcodec == 0x12) /* G.729a */ - { - if (zt_tc_sanitycheck(zth, rlen) && (rlen == G729_BYTES)) - { - for (i = 0; i < rlen; i++) - chars[i] = readchunk[i+54]; + } + dr->head = 0; + dr->tail = 0; + dr->count = 0; + spin_unlock_bh(&dr->lock); + pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE, + dr->desc, dr->desc_dma); +} - zth->dstlen += rlen; - zth->dstsamples = zth->dstlen * 8; +static void wctc4xxp_cleanup_command_list(struct wcdte *wc) +{ + struct tcb *cmd; + LIST_HEAD(local_list); + + spin_lock_bh(&wc->cmd_list_lock); + list_splice_init(&wc->cmd_list, &local_list); + list_splice_init(&wc->waiting_for_response_list, &local_list); + spin_unlock_bh(&wc->cmd_list_lock); + + while(!list_empty(&local_list)) { + cmd = list_entry(local_list.next, struct tcb, node); + list_del_init(&cmd->node); + free_cmd(cmd); + } +} - } else { - ztc->errorstatus = -EOVERFLOW; - } +/** + * The command list is used to store commands that couldn't fit in the tx + * descriptor list when they were requested. + */ +static void +wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd) +{ + spin_lock_bh(&wc->cmd_list_lock); + list_add_tail(&cmd->node, &wc->cmd_list); + spin_unlock_bh(&wc->cmd_list_lock); +} - if (!(zth->dstsamples % G729_SAMPLES)) - { - zt_transcoder_alert(ztc); - } +static void +wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd) +{ + spin_lock_bh(&wc->cmd_list_lock); + list_add_tail(&cmd->node, &wc->waiting_for_response_list); + spin_unlock_bh(&wc->cmd_list_lock); +} + +static void +wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd) +{ + spin_lock_bh(&wc->cmd_list_lock); + list_del_init(&cmd->node); + spin_unlock_bh(&wc->cmd_list_lock); +} + +static void +wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd) +{ + int res; + + if (cmd->data_len < MIN_PACKET_LEN) { + memset((u8*)(cmd->data) + cmd->data_len, 0, + MIN_PACKET_LEN-cmd->data_len); + cmd->data_len = MIN_PACKET_LEN; + } + WARN_ON(cmd->response); + WARN_ON(cmd->flags & TX_COMPLETE); + cmd->timeout = jiffies + HZ/4; + if (cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE)) { + if (cmd->flags & __WAIT_FOR_RESPONSE) { + /* We don't need both an ACK and a response. Let's + * tell the DTE not to generate an ACK, and we'll just + * retry if we do not get the response within the + * timeout period. */ + struct csm_encaps_hdr *hdr = cmd->data; + hdr->control |= SUPPRESS_ACK; } + WARN_ON(!list_empty(&cmd->node)); + wctc4xxp_add_to_response_list(wc, cmd); + mod_timer(&wc->watchdog, jiffies + HZ/2); + } + if (!(cmd->flags & DO_NOT_CAPTURE)) wctc4xxp_net_capture_cmd(wc, cmd); + if ((res=wctc4xxp_submit(wc->txd, cmd))) { + if (-EBUSY == res) { + /* Looks like we're out of room in the descriptor + * ring. We'll add this command to the pending list + * and the interrupt service routine will pull from + * this list as it clears up room in the descriptor + * ring. */ + wctc4xxp_remove_from_response_list(wc, cmd); + wctc4xxp_add_to_command_list(wc, cmd); + } else { + /* Unknown return value... */ + WARN_ON(1); + } + } else { + wctc4xxp_transmit_demand_poll(wc); + } +} + +static int +wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd) +{ + cmd->flags |= DO_NOT_AUTO_FREE; + wctc4xxp_transmit_cmd(wc, cmd); + wait_for_completion(&cmd->complete); + if (cmd->flags & DTE_CMD_TIMEOUT) { + DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n"); + return -EIO; + } + return 0; +} + +static int wctc4xxp_create_channel_pair(struct wcdte *wc, + struct channel_pvt *cpvt, u8 simple, u8 complicated); +static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt); +static int __wctc4xxp_setup_channels(struct wcdte *wc); + +static int +__wctc4xxp_send_cmd(struct wcdte *wc, struct tcb *cmd) +{ + int ret = 0; + wctc4xxp_transmit_cmd(wc, cmd); + wait_for_completion(&cmd->complete); + if (cmd->flags & DTE_CMD_TIMEOUT) { + ret = -EIO; } + free_cmd(cmd); + return ret; } +static void +wctc4xxp_init_state(struct channel_pvt *cpvt, encode_t encoder, + unsigned int channel, struct wcdte *wc) +{ + memset(cpvt, 0, sizeof(*cpvt)); + cpvt->encoder = encoder; + cpvt->wc = wc; + cpvt->chan_in_num = INVALID; + cpvt->chan_out_num = INVALID; + cpvt->ssrc = 0x78; + + cpvt->timeslot_in_num = channel* 2; + cpvt->timeslot_out_num = channel * 2; + if (ENCODER == 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; + spin_lock_bh(&wc->reglock); + val = __wctc4xxp_getctl(wc, addr); + spin_unlock_bh(&wc->reglock); + return val; +} -/* static inline int wcdte_check_descriptor(struct wcdte *wc) */ -static int wcdte_check_descriptor(struct wcdte *wc) +static void +wctc4xxp_cleanup_channel_private(struct wcdte *wc, struct channel_pvt *cpvt) { - int o2 = 0; + struct tcb *cmd, *temp; + LIST_HEAD(local_list); - o2 += ERING_SIZE * 4; - o2 += wc->rdbl * 4; + spin_lock_bh(&cpvt->lock); + list_splice_init(&cpvt->rx_queue, &local_list); + spin_unlock_bh(&cpvt->lock); - if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) { - wc->rxints++; - wcdte_receiveprep(wc, wc->rdbl); - wcdte_reinit_descriptor(wc, 0, wc->rdbl, "rxchk"); - wc->rdbl = (wc->rdbl + 1) % ERING_SIZE; + list_for_each_entry_safe(cmd, temp, &local_list, node) { + list_del(&cmd->node); + free_cmd(cmd); + } +} - return 1; +static int +wctc4xxp_mark_channel_complement_built(struct wcdte *wc, + struct zt_transcoder_channel *dtc) +{ + int index; + struct channel_pvt *cpvt = dtc->pvt; + struct zt_transcoder_channel *compl_dtc; + struct channel_pvt *compl_cpvt; + + BUG_ON(!cpvt); + index = cpvt->timeslot_in_num/2; + BUG_ON(index >= wc->numchannels); + if (cpvt->encoder == 1) { + compl_dtc = &(wc->udecode->channels[index]); + } else { + compl_dtc = &(wc->uencode->channels[index]); } + + /* It shouldn't already have been built... */ + WARN_ON(zt_tc_is_built(compl_dtc)); + compl_dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; + compl_cpvt = compl_dtc->pvt; + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "dtc: %p is the complement to %p\n", compl_dtc, dtc); + compl_cpvt->chan_in_num = cpvt->chan_out_num; + compl_cpvt->chan_out_num = cpvt->chan_in_num; + zt_tc_set_built(compl_dtc); + wctc4xxp_cleanup_channel_private(wc, compl_cpvt); + return 0; } -static void wcdte_init_descriptors(struct wcdte *wc) +static int +do_channel_allocate(struct zt_transcoder_channel *dtc) { - volatile unsigned int *descrip; - dma_addr_t descripdma; - dma_addr_t writedma; - dma_addr_t readdma; - int x; + struct channel_pvt *cpvt = dtc->pvt; + struct wcdte *wc = cpvt->wc; + u8 wctc4xxp_srcfmt; /* Digium Transcoder Engine Source Format */ + u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */ + int res; + + down(&wc->chansem); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Entering %s for channel %p.\n", __FUNCTION__, dtc); + /* Anything on the rx queue now is old news... */ + zt_tc_clear_data_waiting(dtc); + wctc4xxp_cleanup_channel_private(wc, cpvt); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating a new channel: %p.\n", dtc); + wctc4xxp_srcfmt = wctc4xxp_zapfmt_to_dtefmt(dtc->srcfmt); + wctc4xxp_dstfmt = wctc4xxp_zapfmt_to_dtefmt(dtc->dstfmt); + res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt, + wctc4xxp_dstfmt); + if (res) { + /* There was a problem creating the channel.... */ + up(&wc->chansem); + return res; + } + /* Mark this channel as built */ + zt_tc_set_built(dtc); + dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; + /* Mark the channel complement (other half of encoder/decoder pair) as built */ + res = wctc4xxp_mark_channel_complement_built(wc, dtc); + up(&wc->chansem); + zt_transcoder_alert(dtc); + return res; +} + +static int +wctc4xxp_operation_allocate(struct zt_transcoder_channel *dtc) +{ + struct wcdte *wc = ((struct channel_pvt*)(dtc->pvt))->wc; + + if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { + /* The shudown flags can also be set if there is a + * catastrophic failure. */ + return -EIO; + } + + if (zt_tc_is_built(dtc)) { + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Allocating channel %p which is already built.\n", dtc); + return 0; + } + return do_channel_allocate(dtc); +} + +static int +wctc4xxp_operation_release(struct zt_transcoder_channel *dtc) +{ + int res; + int index; + /* This is the 'complimentary channel' to dtc. I.e., if dtc is an + * encoder, compl_dtc is the decoder and vice-versa */ + struct zt_transcoder_channel *compl_dtc; + struct channel_pvt *compl_cpvt; + struct channel_pvt *cpvt = dtc->pvt; + struct wcdte *wc = cpvt->wc; + + BUG_ON(!cpvt); + BUG_ON(!wc); + + if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { + /* The shudown flags can also be set if there is a + * catastrophic failure. */ + return -EIO; + } + + /* !!!SRR!!! change this back to down after troubleshooting */ + if (down_interruptible(&wc->chansem)) { + return -EINTR; + } + /* Remove any packets that are waiting on the outbound queue. */ + wctc4xxp_cleanup_channel_private(wc, cpvt); + index = cpvt->timeslot_in_num/2; + BUG_ON(index >= wc->numchannels); + if (ENCODER == cpvt->encoder) { + compl_dtc = &(wc->udecode->channels[index]); + } else { + compl_dtc = &(wc->uencode->channels[index]); + } + BUG_ON(!compl_dtc); + if (!zt_tc_is_built(compl_dtc)) { + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Releasing a channel that was never built.\n"); + res = 0; + goto error_exit; + } + /* If the channel complement (other half of the encoder/decoder pair) is + * being used... */ + if (zt_tc_is_busy(compl_dtc)) { + res = -EBUSY; + goto error_exit; + } + if ((res = wctc4xxp_destroy_channel_pair(wc, cpvt))) { + goto error_exit; + } + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %p\n", dtc); + /* Mark this channel as not built */ + zt_tc_clear_built(dtc); + dtc->built_fmts = 0; + cpvt->chan_in_num = INVALID; + cpvt->chan_out_num = INVALID; + /* Mark the channel complement as not built */ + zt_tc_clear_built(compl_dtc); + compl_dtc->built_fmts = 0; + compl_cpvt = compl_dtc->pvt; + compl_cpvt->chan_in_num = INVALID; + compl_cpvt->chan_out_num = INVALID; + cpvt->wctc4xxp_seqno_rcv = 0; +error_exit: + up(&wc->chansem); + return res; +} + +static inline struct tcb* +get_ready_cmd(struct zt_transcoder_channel *dtc) +{ + struct channel_pvt *cpvt = dtc->pvt; + struct tcb *cmd; + spin_lock_bh(&cpvt->lock); + if (!list_empty(&cpvt->rx_queue)) { + WARN_ON(!zt_tc_is_data_waiting(dtc)); + cmd = list_entry(cpvt->rx_queue.next, struct tcb, node); + list_del_init(&cmd->node); + } else { + cmd = NULL; + } + if (list_empty(&cpvt->rx_queue)) { + zt_tc_clear_data_waiting(dtc); + } + spin_unlock_bh(&cpvt->lock); + return cmd; +} + +/* Called with a buffer in which to copy a transcoded frame. */ +static ssize_t +wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) +{ + ssize_t ret; + struct zt_transcoder_channel *dtc = file->private_data; + struct channel_pvt *cpvt = dtc->pvt; + struct wcdte *wc = cpvt->wc; + struct tcb *cmd; + struct rtp_packet *packet; + ssize_t payload_bytes; + u16 rtp_eseq; + + BUG_ON(!dtc); + BUG_ON(!cpvt); + + if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { + /* The shudown flags can also be set if there is a + * catastrophic failure. */ + return -EIO; + } + + if (!(cmd = get_ready_cmd(dtc))) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } else { + ret = wait_event_interruptible(dtc->ready, + zt_tc_is_data_waiting(dtc)); + if (-ERESTARTSYS == ret) { + /* Signal interrupted the wait */ + return -EINTR; + } else { + /* List went not empty. */ + cmd = get_ready_cmd(dtc); + } + } + } + + BUG_ON(!cmd); + packet = cmd->data; - descrip = wc->descripchunk; - descripdma = wc->descripdma; - writedma = wc->writedma; - readdma = wc->readdma; - - for (x=0;xdescripdma; - - /* Transmit descriptor */ - descrip[0 ] = cpu_to_le32(0x00000000); - descrip[1 ] = cpu_to_le32(0xe5800000 | (SFRAME_SIZE)); - descrip[2 ] = cpu_to_le32(writedma + x*SFRAME_SIZE); - descrip[3 ] = cpu_to_le32(descripdma); - - /* Receive descriptor */ - descrip[0 + ERING_SIZE * 4] = cpu_to_le32(0x80000000); - descrip[1 + ERING_SIZE * 4] = cpu_to_le32(0x01000000 | (SFRAME_SIZE)); - descrip[2 + ERING_SIZE * 4] = cpu_to_le32(readdma + x*SFRAME_SIZE); - descrip[3 + ERING_SIZE * 4] = cpu_to_le32(descripdma + ERING_SIZE * 16); + payload_bytes = be16_to_cpu(packet->udphdr.len) - sizeof(struct rtphdr) - + sizeof(struct udphdr); + + if (count < payload_bytes) { + DTE_PRINTK(ERR, "Insufficient room to copy read data. Dropping packet.\n"); + free_cmd(cmd); + return -EFBIG; + } + + atomic_inc(&cpvt->stats.packets_received); + + if (0 == cpvt->wctc4xxp_seqno_rcv) { + cpvt->wctc4xxp_seqno_rcv = 1; + cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno); + } else { + rtp_eseq = ++cpvt->last_dte_seqno; + if ( packet->rtphdr.seqno != rtp_eseq ) + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Bad seqno from DTE! [%04X][%d][%d][%d]\n", + be16_to_cpu(packet->rtphdr.seqno), + (be16_to_cpu(packet->udphdr.dest) - 0x5000), + be16_to_cpu(packet->rtphdr.seqno), + cpvt->last_dte_seqno); + + cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno); + } + + if (unlikely(copy_to_user(frame, &packet->payload[0], payload_bytes))) { + DTE_PRINTK(ERR, "Failed to copy data in %s\n", __FUNCTION__); + free_cmd(cmd); + return -EFAULT; + } + + free_cmd(cmd); + + return payload_bytes; +} + +/* Called with a frame in the srcfmt that is to be transcoded into the dstfmt. */ +static ssize_t +wctc4xxp_write(struct file *file, const char __user *frame, size_t count, loff_t *ppos) +{ + struct zt_transcoder_channel *dtc = file->private_data; + struct channel_pvt *cpvt = dtc->pvt; + struct wcdte *wc = cpvt->wc; + struct tcb *cmd; + + 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; + } + + if (!test_bit(ZT_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 (ZT_FORMAT_G723_1 == dtc->srcfmt) { + if (G723_5K_BYTES != count) { + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Trying to transcode packet into G723 format " \ + "that is %Zu bytes instead of the expected " \ + "%d bytes.\n", count, G723_5K_BYTES); + return -EINVAL; + } + } + + if (!(cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count))) { + return -ENOMEM; + } + /* Copy the data directly from user space into the command buffer. */ + if (copy_from_user(&((struct rtp_packet*)(cmd->data))->payload[0], frame, count)) { + DTE_PRINTK(ERR, "Failed to copy packet from userspace.\n"); + free_cmd(cmd); + return -EFAULT; + } + cpvt->seqno += 1; + cpvt->timestamp += count; + + DTE_DEBUG(DTE_DEBUG_RTP_TX, + "Sending packet of %Zu byte on channel (%p).\n", count, dtc); + + wctc4xxp_transmit_cmd(wc, cmd); + atomic_inc(&cpvt->stats.packets_sent); + + return count; +} + +static void +wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel) +{ + struct tcb *cmd; + struct csm_encaps_hdr *hdr; + if (!(cmd = __alloc_cmd(ALLOC_FLAGS, 0))) { + WARN_ON(1); + return; + } + hdr = cmd->data; + BUG_ON(sizeof(*hdr) > cmd->data_len); + setup_common_header(wc, hdr); + hdr->op_code = cpu_to_be16(0x0001); + hdr->seq_num = seqno; + hdr->control = 0xe0; + hdr->channel = channel; + + cmd->data_len = sizeof(*hdr); + wctc4xxp_transmit_cmd(wc, cmd); +} + +static void +do_rx_response_packet(struct wcdte *wc, struct tcb *cmd) +{ + const struct csm_encaps_hdr *listhdr; + const struct csm_encaps_hdr *rxhdr; + struct tcb *pos; + struct tcb *temp; + + rxhdr = cmd->data; + spin_lock_bh(&wc->cmd_list_lock); + list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { + listhdr = pos->data; + if ((listhdr->function == rxhdr->function) && + (listhdr->channel == rxhdr->channel)) { + list_del_init(&pos->node); + pos->flags &= ~(__WAIT_FOR_RESPONSE); + WARN_ON(pos->response); + pos->response = cmd; + complete(&pos->complete); + break; + } + } + spin_unlock_bh(&wc->cmd_list_lock); +} + +static void +do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd) +{ + const struct csm_encaps_hdr *listhdr; + const struct csm_encaps_hdr *rxhdr; + struct tcb *pos; + struct tcb *temp; + + rxhdr = cmd->data; + + spin_lock_bh(&wc->cmd_list_lock); + list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { + listhdr = pos->data; + if (cpu_to_be16(0xefed) == listhdr->ethhdr.h_proto) { + wc->seq_num = (rxhdr->seq_num + 1) & 0xff; + WARN_ON(!(pos->flags & DO_NOT_AUTO_FREE)); + list_del_init(&pos->node); + complete(&pos->complete); + } else if ((listhdr->seq_num == rxhdr->seq_num) && + (listhdr->channel == rxhdr->channel)) { + if (pos->flags & __WAIT_FOR_RESPONSE) { + pos->flags &= ~(__WAIT_FOR_ACK); + } else { + list_del_init(&pos->node); + + if (pos->flags & DO_NOT_AUTO_FREE) { + complete(&pos->complete); + } else { + free_cmd(pos); + } + } + break; + } + } + spin_unlock_bh(&wc->cmd_list_lock); + + /* There is never a reason to store up the ack packets. */ + free_cmd(cmd); +} + +static inline int +is_response(const struct csm_encaps_hdr *hdr) +{ + return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0; +} + +static void +receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) +{ + const struct csm_encaps_hdr *hdr = cmd->data; + + if (!(hdr->control & MESSAGE_PACKET)) { + + if (!(hdr->control & SUPPRESS_ACK)) { + wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); + } + + if (is_response(hdr)) { + do_rx_response_packet(wc, cmd); + } else if (0xc1 == hdr->type) { + if (0x75 == hdr->class) { + DTE_PRINTK(WARNING, + "Received alert (0x%04x) from dsp\n", + le16_to_cpu(hdr->params[0])); + } + free_cmd(cmd); + } else if (0xd4 == hdr->type) { + if (hdr->params[0] != le16_to_cpu(0xffff)) { + DTE_PRINTK(WARNING, + "DTE Failed self test (%04x).\n", + le16_to_cpu(hdr->params[0])); + } else if (hdr->params[1] != le16_to_cpu(0x000c)) { + DTE_PRINTK(WARNING, + "Unexpected ERAM status (%04x).\n", + le16_to_cpu(hdr->params[1])); + } else { + wctc4xxp_set_ready(wc); + wake_up(&wc->waitq); + } + free_cmd(cmd); + } else { + DTE_PRINTK(WARNING, "Unknown command type received. %02x\n", hdr->type); + free_cmd(cmd); + } + } else { + do_rx_ack_packet(wc, cmd); + } +} + +static void +queue_rtp_packet(struct wcdte *wc, struct tcb *cmd) +{ + int index; + struct zt_transcoder_channel *dtc; + struct channel_pvt *cpvt; + struct rtp_packet *packet = cmd->data; + + index = (be16_to_cpu(packet->udphdr.dest) - 0x5000) / 2; + if (unlikely(index >= wc->numchannels)) { + DTE_PRINTK(ERR, "Invalid channel number in response from DTE.\n"); + free_cmd(cmd); + return; + } + + switch (packet->rtphdr.type) { + case 0x00: + case 0x08: + dtc = &(wc->udecode->channels[index]); + break; + case 0x04: + case 0x12: + dtc = &(wc->uencode->channels[index]); + break; + default: + DTE_PRINTK(ERR, "Unknown codec in packet (0x%02x).\n",\ + packet->rtphdr.type); + free_cmd(cmd); + return; + } + + cpvt = dtc->pvt; + spin_lock_bh(&cpvt->lock); + list_add_tail(&cmd->node, &cpvt->rx_queue); + spin_unlock_bh(&cpvt->lock); + zt_tc_set_data_waiting(dtc); + zt_transcoder_alert(dtc); + return; +} + +static inline void +wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd) +{ + const struct ethhdr *ethhdr = (const struct ethhdr*)(cmd->data); + + if (cpu_to_be16(ETH_P_IP) == ethhdr->h_proto) { + queue_rtp_packet(wc, cmd); + } else if (cpu_to_be16(ETH_P_CSM_ENCAPS) == ethhdr->h_proto) { + receive_csm_encaps_packet(wc, cmd); + } else { + DTE_PRINTK(WARNING, + "Unknown packet protocol recieved: %04x.\n", + be16_to_cpu(ethhdr->h_proto)); + free_cmd(cmd); + } +} + +static inline void service_dte(struct wcdte *wc) +{ + struct tcb *cmd; + + /* + * Process the received packets + */ + while((cmd = wctc4xxp_retrieve(wc->rxd))) { + struct tcb *newcmd; + + wctc4xxp_net_capture_cmd(wc, cmd); + + if(!(newcmd = __alloc_cmd(ALLOC_FLAGS, 0))) { + DTE_PRINTK(ERR, "Out of memory in %s.\n", __FUNCTION__); + } else { + newcmd->data = kmalloc(1518, ALLOC_FLAGS); + if (!newcmd->data) { + DTE_PRINTK(ERR, "out of memory in %s " \ + "again.\n", __FUNCTION__); + } + newcmd->data_len = 1518; + if (wctc4xxp_submit(wc->rxd, newcmd)) { + DTE_PRINTK(ERR, "Failed submit in %s\n", __FUNCTION__); + free_cmd(newcmd); + } + wctc4xxp_receive_demand_poll(wc); + } + wctc4xxp_receiveprep(wc, cmd); + } + wctc4xxp_receive_demand_poll(wc); - /* Advance descriptor */ - descrip += 4; - } + /* + * Process the transmit packets + */ + while((cmd = wctc4xxp_retrieve(wc->txd))) { + if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) { + spin_lock_bh(&wc->cmd_list_lock); + list_del_init(&cmd->node); + spin_unlock_bh(&wc->cmd_list_lock); + if (DO_NOT_AUTO_FREE & cmd->flags) { + complete(&cmd->complete); + } else { + free_cmd(cmd); + } + } + /* We've freed up a spot in the hardware ring buffer. If + * another packet is queued up, let's submit it to the + * hardware. */ + spin_lock_bh(&wc->cmd_list_lock); + if (!list_empty(&wc->cmd_list)) { + cmd = list_entry(wc->cmd_list.next, struct tcb, node); + list_del_init(&cmd->node); + } else { + cmd = NULL; + } + spin_unlock_bh(&wc->cmd_list_lock); + + if (cmd) { + wctc4xxp_transmit_cmd(wc, cmd); + } + } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -static void dte_wque_run(struct work_struct *work) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void deferred_work_func(void *param) { - struct wcdte *wc = container_of(work, struct wcdte, dte_work); + struct wcdte *wc = param; #else -static void dte_wque_run(void *work_data) +static void deferred_work_func(struct work_struct *work) { - struct wcdte *wc = work_data; + struct wcdte *wc = container_of(work, struct wcdte, deferred_work); #endif - int res; - - do { - res = wcdte_check_descriptor(wc); - } while(res); - - transmit_demand(wc); + service_dte(wc); } -ZAP_IRQ_HANDLER(wcdte_interrupt) +ZAP_IRQ_HANDLER(wctc4xxp_interrupt) { struct wcdte *wc = dev_id; - unsigned int ints; + u32 ints; + u32 reg; +#define TX_COMPLETE_INTERRUPT 0x00000001 +#define RX_COMPLETE_INTERRUPT 0x00000040 +#define NORMAL_INTERRUPTS (TX_COMPLETE_INTERRUPT | RX_COMPLETE_INTERRUPT) /* Read and clear interrupts */ - ints = wcdte_getctl(wc, 0x0028); - wcdte_setctl(wc, 0x0028, ints); + ints = __wctc4xxp_getctl(wc, 0x0028); + ints &= wc->intmask; + if (!ints) return IRQ_NONE; - ints &= wc->intmask; - if (ints & 0x00000041) { - wc->wqueints = ints; - queue_work(wc->dte_wq, &wc->dte_work); - } - - if ((ints & 0x00008000) && debug) - printk("wcdte: Abnormal Interrupt: "); + if (likely(ints & NORMAL_INTERRUPTS)) { + reg = 0; + if (ints & TX_COMPLETE_INTERRUPT) { + reg |= TX_COMPLETE_INTERRUPT; + } + if (ints & RX_COMPLETE_INTERRUPT) { + reg |= RX_COMPLETE_INTERRUPT; + } +#if DEFERRED_PROCESSING == WORKQUEUE + schedule_work(&wc->deferred_work); +#elif DEFERRED_PROCESSING == INTERRUPT +#error "You will need to change the locks if you want to run the processing in the interrupt handler." +#else +#error "Define a deferred processing function in kernel/wctc4xxp/wctc4xxp.h" +#endif + __wctc4xxp_setctl(wc, 0x0028, reg); + } else { + if ((ints & 0x00008000) && debug) + DTE_PRINTK(INFO, "Abnormal Interrupt.\n"); - if ((ints & 0x00002000) && debug) - printk("wcdte: Fatal Bus Error INT\n"); + if ((ints & 0x00002000) && debug) + DTE_PRINTK(INFO, "Fatal Bus Error INT\n"); - if ((ints & 0x00000100) && debug) - printk("wcdte: Receive Stopped INT\n"); + if ((ints & 0x00000100) && debug) + DTE_PRINTK(INFO, "Receive Stopped INT\n"); - if ((ints & 0x00000080) && debug) - printk("wcdte: Receive Desciptor Unavailable INT\n"); + if ((ints & 0x00000080) && debug) { + DTE_PRINTK(INFO, "Receive Desciptor Unavailable INT " \ + "(%d)\n", wctc4xxp_getcount(wc->rxd)); + } - if ((ints & 0x00000020) && debug) - printk("wcdte: Transmit Under-flow INT\n"); + if ((ints & 0x00000020) && debug) + DTE_PRINTK(INFO, "Transmit Under-flow INT\n"); - if ((ints & 0x00000008) && debug) - printk("wcdte: Jabber Timer Time-out INT\n"); + if ((ints & 0x00000008) && debug) + DTE_PRINTK(INFO, "Jabber Timer Time-out INT\n"); - if ((ints & 0x00000004) && debug) - printk("wcdte: Transmit Descriptor Unavailable INT\n"); + if ((ints & 0x00000004) && debug) + ; // printk("wcdte: Transmit Descriptor Unavailable INT\n"); - if ((ints & 0x00000002) && debug) - printk("wcdte: Transmit Processor Stopped INT\n"); + if ((ints & 0x00000002) && debug) + DTE_PRINTK(INFO, "Transmit Processor Stopped INT\n"); - return IRQ_RETVAL(1); - + /* Clear all the pending interrupts. */ + __wctc4xxp_setctl(wc, 0x0028, ints); + } + return IRQ_HANDLED; } -static int wcdte_hardware_init(struct wcdte *wc) +static int +wctc4xxp_hardware_init(struct wcdte *wc) { /* Hardware stuff */ - unsigned int reg; + u32 reg; unsigned long newjiffies; - - /* Initialize descriptors */ - wcdte_init_descriptors(wc); + u8 cache_line_size; + const u32 DEFAULT_PCI_ACCESS = 0xfff80000; /* Enable I/O Access */ - pci_read_config_dword(wc->dev, 0x0004, ®); + pci_read_config_dword(wc->pdev, 0x0004, ®); reg |= 0x00000007; - pci_write_config_dword(wc->dev, 0x0004, reg); - - wcdte_setctl(wc, 0x0000, 0xFFF88001); + pci_write_config_dword(wc->pdev, 0x0004, reg); - newjiffies = jiffies + HZ/10; - while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)); + if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size)) { + /* \todo Print an error message... */ + return -EIO; + } + switch (cache_line_size) { + case 0x08: + reg = DEFAULT_PCI_ACCESS | (0x1 << 14); + break; + case 0x10: + reg = DEFAULT_PCI_ACCESS | (0x2 << 14); + break; + case 0x20: + reg = DEFAULT_PCI_ACCESS | (0x3 << 14); + break; + default: + reg = 0xfe584202; + break; + } + + reg |= ((wc->txd->padding / sizeof(u32)) << 2) & 0x7c; + + /* Reset the DTE... */ + wctc4xxp_setctl(wc, 0x0000, reg | 1); + newjiffies = jiffies + HZ; /* One second timeout */ + /* ...and wait for it to come out of reset. */ + while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) { + msleep(1); + } - wcdte_setctl(wc, 0x0000, 0xFFFA0000); + wctc4xxp_setctl(wc, 0x0000, reg); /* Configure watchdogs, access, etc */ - wcdte_setctl(wc, 0x0030, 0x00280048); - wcdte_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); + wctc4xxp_setctl(wc, 0x0030, 0x00280048); + wctc4xxp_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); - reg = wcdte_getctl(wc, 0x00fc); - wcdte_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); + reg = wctc4xxp_getctl(wc, 0x00fc); + wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); - reg = wcdte_getctl(wc, 0x00fc); + reg = wctc4xxp_getctl(wc, 0x00fc); return 0; } -static void wcdte_setintmask(struct wcdte *wc, unsigned int intmask) +static void +wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask) { wc->intmask = intmask; - wcdte_setctl(wc, 0x0038, intmask); + wctc4xxp_setctl(wc, 0x0038, intmask); } -static void wcdte_enable_interrupts(struct wcdte *wc) +static void +wctc4xxp_enable_interrupts(struct wcdte *wc) { - /* Enable interrupts */ - if (!debug) - wcdte_setintmask(wc, 0x00010041); - else - wcdte_setintmask(wc, 0x0001A1EB); + wctc4xxp_setintmask(wc, 0x000180c1); + // wctc4xxp_setintmask(wc, 0xffffffff); } -static void wcdte_start_dma(struct wcdte *wc) +static void +wctc4xxp_start_dma(struct wcdte *wc) { - unsigned int reg; + int res; + int i; + u32 reg; + struct tcb *cmd; + + for (i = 0; i < DRING_SIZE; ++i) { + if (!(cmd = alloc_cmd())) { + WARN(); + return; + } + cmd->data_len = SFRAME_SIZE; + if ((res=wctc4xxp_submit(wc->rxd, cmd))) { + /* When we're starting the DMA, we should always be + * able to fill the ring....so something is wrong + * here. */ + WARN(); + free_cmd(cmd); + break; + } + } wmb(); - wcdte_setctl(wc, 0x0020, wc->descripdma); - wcdte_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE)); + wctc4xxp_setctl(wc, 0x0020, wc->txd->desc_dma); + wctc4xxp_setctl(wc, 0x0018, wc->rxd->desc_dma); + /* Start receiver/transmitter */ - reg = wcdte_getctl(wc, 0x0030); - wcdte_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */ - wcdte_setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */ - reg = wcdte_getctl(wc, 0x0028); - wcdte_setctl(wc, 0x0028, reg); + reg = wctc4xxp_getctl(wc, 0x0030); + wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */ + wctc4xxp_receive_demand_poll(wc); + reg = wctc4xxp_getctl(wc, 0x0028); + wctc4xxp_setctl(wc, 0x0028, reg); } -static void wcdte_stop_dma(struct wcdte *wc) +static void +wctc4xxp_stop_dma(struct wcdte *wc) { /* Disable interrupts and reset */ unsigned int reg; + unsigned long newjiffies; /* Disable interrupts */ - wcdte_setintmask(wc, 0x00000000); - wcdte_setctl(wc, 0x0084, 0x00000000); - wcdte_setctl(wc, 0x0048, 0x00000000); + wctc4xxp_setintmask(wc, 0x00000000); + wctc4xxp_setctl(wc, 0x0084, 0x00000000); + wctc4xxp_setctl(wc, 0x0048, 0x00000000); /* Reset the part to be on the safe side */ - reg = wcdte_getctl(wc, 0x0000); + reg = wctc4xxp_getctl(wc, 0x0000); reg |= 0x00000001; - wcdte_setctl(wc, 0x0000, reg); -} + wctc4xxp_setctl(wc, 0x0000, reg); -static void wcdte_disable_interrupts(struct wcdte *wc) -{ - /* Disable interrupts */ - wcdte_setintmask(wc, 0x00000000); - wcdte_setctl(wc, 0x0084, 0x00000000); + newjiffies = jiffies + HZ; /* One second timeout */ + /* We'll wait here for the part to come out of reset */ + while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) { + msleep(1); + } } -static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int wait_mode) +static void +wctc4xxp_disable_interrupts(struct wcdte *wc) { - int ret; - - - if (wait_mode == 1) - ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout); - else if (wait_mode == 2) - ret = wait_event_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout); - else { - if (!debug_notimeout) { - ret = wait_event_timeout(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout); - } - else { - ret = wait_event_interruptible(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask))); - if (ret == 0) - ret = 1; - } - } - wc->rcvflags = 0; - wc->last_rcommand = 0; - wc->last_seqno = 0; - - if (ret < 0) - { - if (debug) - printk("wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret); - return(1); - } - if (ret == 0) - { - if (debug) - printk("wcdte error: Waitfor CSMENCAPS response timed out (ret = %d) (cmd_snt = %04X)\n", ret, wc->last_command_sent); - if (debug_des) { - down(&wc->cmdqsem); - __dump_descriptors(wc); - up(&wc->cmdqsem); - } - return(2); - } - if (wait_mode == 0) - wc->last_command_sent = 999; - wc->last_rseqno = 999; - return(0); + /* Disable interrupts */ + wctc4xxp_setintmask(wc, 0x00000000); + wctc4xxp_setctl(wc, 0x0084, 0x00000000); } +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 -static int wcdte_read_phy(struct wcdte *wc, int location) +static int +wctc4xxp_read_phy(struct wcdte *wc, int location) { int i; long mdio_addr = 0x0048; @@ -1363,34 +2254,36 @@ static int wcdte_read_phy(struct wcdte *wc, int location) /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { - wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); - wcdte_getctl(wc, mdio_addr); - wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); + wctc4xxp_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } + /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval); - wcdte_getctl(wc, mdio_addr); - wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); + wctc4xxp_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { - wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN); - wcdte_getctl(wc, mdio_addr); - retval = (retval << 1) | ((wcdte_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); + wctc4xxp_getctl(wc, mdio_addr); + retval = (retval << 1) | ((wctc4xxp_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } retval = (retval>>1) & 0xffff; return retval; } -void wcdte_write_phy(struct wcdte *wc, int location, int value) +static void +wctc4xxp_write_phy(struct wcdte *wc, int location, int value) { int i; int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value; @@ -1398,624 +2291,991 @@ void wcdte_write_phy(struct wcdte *wc, int location, int value) /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { - wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); - wcdte_getctl(wc, mdio_addr); - wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); + wctc4xxp_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval); - wcdte_getctl(wc, mdio_addr); - wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); + wctc4xxp_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { - wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN); - wcdte_getctl(wc, mdio_addr); - wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); - wcdte_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); + wctc4xxp_getctl(wc, mdio_addr); + wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + wctc4xxp_getctl(wc, mdio_addr); } return; } -static int wcdte_boot_processor(struct wcdte *wc, const struct firmware *firmware, int full) +static int +wctc4xxp_wait_for_link(struct wcdte *wc) { - int i, j, byteloc, last_byteloc, length, delay_count; - unsigned int reg, ret; + int reg; + unsigned int delay_count = 0; + do { + reg = wctc4xxp_getctl(wc, 0x00fc); + mdelay(2); + delay_count++; + + if (delay_count >= 5000) { + DTE_PRINTK(ERR, "Failed to link to DTE processor!\n"); + return -EIO; + } + } while ((reg & 0xE0000000) != 0xE0000000); + return 0; +} + +static int +wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware) +{ + unsigned int byteloc; + unsigned int last_byteloc; + unsigned int length; + struct tcb *cmd; + + byteloc = 17; + + if (!(cmd = alloc_cmd())) { + return -ENOMEM; + } + if (1518 > cmd->data_len) { + cmd->data = kmalloc(1518, GFP_KERNEL); + if (!(cmd->data)) { + free_cmd(cmd); + return -ENOMEM; + } + cmd->data_len = 1518; + } + while (byteloc < (firmware->size-20)) { + last_byteloc = byteloc; + length = (firmware->data[byteloc] << 8) | firmware->data[byteloc+1]; + byteloc += 2; + cmd->data_len = length; + BUG_ON(length > cmd->data_len); + memcpy(cmd->data, &firmware->data[byteloc], length); + byteloc += length; + cmd->flags = WAIT_FOR_ACK; + wctc4xxp_transmit_cmd(wc, cmd); + wait_for_completion(&cmd->complete); + if (cmd->flags & DTE_CMD_TIMEOUT) { + free_cmd(cmd); + DTE_PRINTK(ERR, "Failed to load firmware.\n"); + return -EIO; + } + } + free_cmd(cmd); + if (!wait_event_timeout(wc->waitq, wctc4xxp_is_ready(wc), 15*HZ)) { + DTE_PRINTK(ERR, "Failed to boot firmware.\n"); + return -EIO; + } + return 0; +} -#ifndef USE_TEST_HW +static int +wctc4xxp_turn_off_booted_led(struct wcdte *wc) +{ + int ret = 0; + int reg; /* Turn off auto negotiation */ - wcdte_write_phy(wc, 0, 0x2100); - if (debug) - printk("wcdte: PHY register 0 = %X", wcdte_read_phy(wc, 0)); + wctc4xxp_write_phy(wc, 0, 0x2100); + DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n", + wctc4xxp_read_phy(wc, 0)); /* Set reset */ - wcdte_setctl(wc, 0x00A0, 0x04000000); + wctc4xxp_setctl(wc, 0x00A0, 0x04000000); - /* Wait 1000msec to ensure processor reset */ + /* Wait 4 ms to ensure processor reset */ mdelay(4); /* Clear reset */ - wcdte_setctl(wc, 0x00A0, 0x04080000); - - /* Waitfor ethernet link */ - delay_count = 0; - do - { - reg = wcdte_getctl(wc, 0x00fc); - mdelay(2); - delay_count++; - - if (delay_count >= 5000) - { - printk("wcdte error: Failed to link to DTE processor!\n"); - return(1); - } - } while ((reg & 0xE0000000) != 0xE0000000); + wctc4xxp_setctl(wc, 0x00A0, 0x04080000); + /* Wait for the ethernet link */ + if ((ret = wctc4xxp_wait_for_link(wc))) { + return ret; + } /* Turn off booted LED */ - wcdte_setctl(wc, 0x00A0, 0x04084000); + wctc4xxp_setctl(wc, 0x00A0, 0x04084000); + reg = wctc4xxp_getctl(wc, 0x00fc); + DTE_DEBUG(DTE_DEBUG_GENERAL, "LINK STATUS: reg(0xfc) = %X\n", reg); - -#endif + reg = wctc4xxp_getctl(wc, 0x00A0); - reg = wcdte_getctl(wc, 0x00fc); - if (debug) - printk("wcdte: LINK STATUS: reg(0xfc) = %X\n", reg); - - reg = wcdte_getctl(wc, 0x00A0); + return ret; +} - byteloc = 17; - j = 0; - do - { - last_byteloc = byteloc; +static void +wctc4xxp_turn_on_booted_led(struct wcdte *wc) +{ + wctc4xxp_setctl(wc, 0x00A0, 0x04080000); +} - length = (firmware->data[byteloc] << 8) |firmware->data[byteloc+1]; - byteloc += 2; - - down(&wc->cmdqsem); - if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) - printk("wcdte error: cmdq is full.\n"); - else - { - wc->cmdq[wc->cmdq_wndx].cmdlen = length; - for (i = 0; i < length; i++) - wc->cmdq[wc->cmdq_wndx].cmd[i] = firmware->data[byteloc++]; - wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; - } - - ret = __transmit_demand(wc); - up(&wc->cmdqsem); - - ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 1); - if (ret == 1) - return(1); - else if (ret == 2) /* Retransmit if dte processor times out */ - byteloc = last_byteloc; - j++; - - if (!full && (byteloc > 189)) { /* Quit if not fully booting */ - wcdte_setctl(wc, 0x00A0, 0x04080000); - return 0; - } +static int +wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware) +{ + int ret; + wctc4xxp_turn_off_booted_led(wc); - } while (byteloc < firmware->size-20); - wc->timeout = 10 * HZ; - wc->last_command_sent = 0; - if (wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 1)) - return(1); + if ((ret = wctc4xxp_load_firmware(wc, firmware))) { + return ret; + } - /* Turn on booted LED */ - wcdte_setctl(wc, 0x00A0, 0x04080000); - if(debug) - printk("wcdte: Successfully booted DTE processor.\n"); + wctc4xxp_turn_on_booted_led(wc); - return(0); + DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n"); + return 0; } -static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2) +static int +wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, + u8 simple, u8 complicated) { - int length = 0; - unsigned char chan1, chan2; - struct zt_transcoder_channel *ztc1, *ztc2; - struct dte_state *st1, *st2; - if(complicated == DTE_FORMAT_G729A) - length = G729_LENGTH; - else if (complicated == DTE_FORMAT_G723_1) - length = G723_LENGTH; + int res; + int length; + u8 chan1, chan2; + struct zt_transcoder_channel *dtc1, *dtc2; + struct channel_pvt *cpvt1, *cpvt2; + /* \todo what do these part variable names mean? */ + unsigned int timeslot; + unsigned int part2_id; + struct tcb *cmd; + const struct csm_encaps_hdr *hdr; + + + BUG_ON(!wc || !cpvt); + if (cpvt->encoder) { + timeslot = cpvt->timeslot_in_num; + part2_id = cpvt->timeslot_out_num; + } else { + u8 temp; + timeslot = cpvt->timeslot_out_num; + part2_id = cpvt->timeslot_in_num; + temp = simple; + simple = complicated; + complicated = temp; + } + + length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH : + (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0; - /* Create complex channel */ - zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); - zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010); - chan1 = wc->last_rparm1; + if (!(cmd = wctc4xxp_create_channel_cmd(wc, timeslot))) { + return -ENOMEM; + } + if ((res=wctc4xxp_transmit_cmd_and_wait(wc, cmd))) { + free_cmd(cmd); + return res; + } + free_cmd(cmd); - /* Create simple channel */ - zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); - zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010); - chan2 = wc->last_rparm1; + cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, timeslot)); + if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) { + free_cmd(cmd); + return res; + } + WARN_ON(!cmd->response); + hdr = (const struct csm_encaps_hdr*)cmd->response->data; + chan1 = le16_to_cpu(hdr->params[0]);; + free_cmd(cmd); - ztc1 = &(wc->uencode->channels[part1_id/2]); - ztc2 = &(wc->udecode->channels[part2_id/2]); - st1 = ztc1->pvt; - st2 = ztc2->pvt; + if (!(cmd = wctc4xxp_create_channel_cmd(wc, part2_id))) { + return -ENOMEM; + } + if ((res = __wctc4xxp_send_cmd(wc, cmd))) { + return res; + } + cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id)); + cmd->flags |= WAIT_FOR_RESPONSE; + if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) { + return res; + } + WARN_ON(!cmd->response); + hdr = (const struct csm_encaps_hdr*)cmd->response->data; + chan2 = le16_to_cpu(hdr->params[0]);; + free_cmd(cmd); + + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "DTE is using the following channels chan1: %d chan2: %d\n", chan1, chan2); + + BUG_ON(timeslot/2 >= wc->numchannels); + BUG_ON(part2_id/2 >= wc->numchannels); + dtc1 = &(wc->uencode->channels[timeslot/2]); + dtc2 = &(wc->udecode->channels[part2_id/2]); + cpvt1 = dtc1->pvt; + cpvt2 = dtc2->pvt; + BUG_ON(!cpvt1); + BUG_ON(!cpvt2); /* Configure complex channel */ - zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st1->cmd_seqno++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); - zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); - + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt1->cmd_seqno++, chan1, part2_id, timeslot)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt1->cmd_seqno++, chan1, length, 0)))) { + return res; + } /* Configure simple channel */ - zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st2->cmd_seqno++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); - zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); - -#ifdef QUIET_DSP - zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B); - zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002); - zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B); - zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002); - zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); - zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); -#endif + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt2->cmd_seqno++, chan2, timeslot, part2_id)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt2->cmd_seqno++, chan2, length, 0)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt1->cmd_seqno++, chan1)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt1->cmd_seqno++, chan1)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt2->cmd_seqno++, chan2)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt2->cmd_seqno++, chan2)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt1->cmd_seqno++, chan1)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt2->cmd_seqno++, chan2)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt1->cmd_seqno++, chan1, complicated)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt2->cmd_seqno++, chan2, simple)))) { + return res; + } + + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "DTE has completed setup and connected the two channels together.\n"); - zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st2->cmd_seqno++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); - *dte_chan1 = chan1; - *dte_chan2 = chan2; + /* Save off the channels returned from the DTE so we can use then when + * sending the RTP packets. */ + if (ENCODER == cpvt->encoder) { + cpvt->chan_in_num = chan1; + cpvt->chan_out_num = chan2; + } else { + cpvt->chan_out_num = chan1; + cpvt->chan_in_num = chan2; + } - return 1; + return 0; } -static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2) +static int +wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt) { - struct zt_transcoder_channel *ztc1, *ztc2; - struct dte_state *st1, *st2; + struct zt_transcoder_channel *dtc1, *dtc2; + struct channel_pvt *cpvt1, *cpvt2; + int chan1, chan2; + int res; + + if (cpvt->encoder) { + chan1 = cpvt->chan_in_num; + chan2 = cpvt->chan_out_num; + } else { + chan1 = cpvt->chan_out_num; + chan2 = cpvt->chan_in_num; + } + + if (chan1/2 >= wc->numchannels || chan2/2 >= wc->numchannels) { + DTE_PRINTK(WARNING, + "Invalid channel numbers in %s. chan1:%d chan2: %d\n", + __FUNCTION__, chan1/2, chan2/2); + return 0; + } - ztc1 = &(wc->uencode->channels[chan1/2]); - ztc2 = &(wc->udecode->channels[chan2/2]); - st1 = ztc1->pvt; - st2 = ztc2->pvt; + dtc1 = &(wc->uencode->channels[chan1/2]); + dtc2 = &(wc->udecode->channels[chan2/2]); + cpvt1 = dtc1->pvt; + cpvt2 = dtc2->pvt; /* Turn off both channels */ - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt1->cmd_seqno++, chan1)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt2->cmd_seqno++, chan2)))) { + return res; + } /* Disconnect the channels */ - zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0)))) { + return res; + } /* Remove the channels */ - zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); - zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2)))) { + return res; + } - return 1; + return 0; } -static int __wcdte_setup_channels(struct wcdte *wc) +static int +__wctc4xxp_setup_channels(struct wcdte *wc) { - wc->seq_num = 6; + int res; + struct tcb *cmd; -#ifndef USE_TEST_HW - zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411); - zt_send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412); -#endif + if (!(cmd = alloc_cmd())) { + return -ENOMEM; + } -#ifdef USE_TDM_CONFIG - zt_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417); - zt_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405); - zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); - zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); - zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); - zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); -#endif + __wctc4xxp_create_set_arm_clk_cmd(wc, cmd); + res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); + free_cmd(cmd); + if (res) { + return res; + } - zt_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100); - zt_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302); - zt_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105); - zt_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304); + cmd = wctc4xxp_create_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++)); + res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); + free_cmd(cmd); + if (res) { + return res; + } -#ifdef USE_TDM_CONFIG - zt_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B); -#endif + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++)))) { + return res; + } - zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); - zt_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306); - zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04)))) { + return res; + } + if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++)))) { + return res; + } + return 0; +} -#ifdef USE_TDM_CONFIG - zt_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435); -#endif +static int +wctc4xxp_setup_channels(struct wcdte *wc) +{ + int ret; + if ((ret=down_interruptible(&wc->chansem))) { + WARN(); + return ret; + } + ret = __wctc4xxp_setup_channels(wc); + up(&wc->chansem); - wc->timeout = HZ/10 + 1; /* 100msec */ + return ret; +} - return(0); +static void wctc4xxp_setup_file_operations(struct file_operations *fops) +{ + fops->owner = THIS_MODULE; + fops->read = wctc4xxp_read; + fops->write = wctc4xxp_write; } -static int wcdte_setup_channels(struct wcdte *wc) +static int +initialize_channel_pvt(struct wcdte *wc, encode_t type, + struct channel_pvt **cpvt) { - down(&wc->chansem); - __wcdte_setup_channels(wc); - up(&wc->chansem); + int chan; + *cpvt = kmalloc(sizeof(struct channel_pvt) * wc->numchannels, GFP_KERNEL); + if (!(*cpvt)) { + return -ENOMEM; + } + for (chan = 0; chan < wc->numchannels; ++chan) { + wctc4xxp_init_state((*cpvt) + chan, type, chan, wc); + } + return 0; +} +static int +initialize_transcoder(struct wcdte *wc, unsigned int srcfmts, + unsigned int dstfmts, struct channel_pvt *pvts, + struct zt_transcoder **zt) +{ + int chan; + *zt = zt_transcoder_alloc(wc->numchannels); + if (!(*zt)) { + return -ENOMEM; + } + (*zt)->srcfmts = srcfmts; + (*zt)->dstfmts = dstfmts; + (*zt)->allocate = wctc4xxp_operation_allocate; + (*zt)->release = wctc4xxp_operation_release; + wctc4xxp_setup_file_operations(&((*zt)->fops)); + for (chan = 0; chan < wc->numchannels; ++chan) { + (*zt)->channels[chan].pvt = &pvts[chan]; + } return 0; } -static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int initialize_encoders(struct wcdte *wc, unsigned int complexfmts) { - int res, reg; - struct wcdte *wc; - struct wcdte_desc *d = (struct wcdte_desc *)ent->driver_data; - int x; - static int initd_ifaces=0; - unsigned char g729_numchannels, g723_numchannels, min_numchannels, dte_firmware_ver, dte_firmware_ver_minor; - unsigned int complexfmts; + int res; + if ((res = initialize_channel_pvt(wc, ENCODER, &wc->encoders))) { + return res; + } + if ((res = initialize_transcoder(wc, + ZT_FORMAT_ULAW | ZT_FORMAT_ALAW, + complexfmts, + wc->encoders, + &wc->uencode))) + { + return res; + } + sprintf(wc->uencode->name, "DTE Encoder"); + return res; +} + +static int +initialize_decoders(struct wcdte *wc, unsigned int complexfmts) +{ + int res; + if ((res = initialize_channel_pvt(wc, DECODER, &wc->decoders))) { + return res; + } + if ((res = initialize_transcoder(wc, + complexfmts, + ZT_FORMAT_ULAW | ZT_FORMAT_ALAW, + wc->decoders, + &wc->udecode))) + { + return res; + } + + sprintf(wc->udecode->name, "DTE Decoder"); + return res; +} + +static void +wctc4xxp_send_commands(struct wcdte *wc, struct list_head *to_send) +{ + struct tcb *cmd; + while (!list_empty(to_send)) { + cmd = container_of(to_send->next, struct tcb, node); + list_del_init(&cmd->node); + wctc4xxp_transmit_cmd(wc, cmd); + } +} + +static void +wctc4xxp_watchdog(unsigned long data) +{ + struct wcdte *wc = (struct wcdte *)data; + struct tcb *cmd, *temp; + LIST_HEAD(cmds_to_retry); + const int MAX_RETRIES = 5; + + spin_lock(&wc->cmd_list_lock); + /* Go through the list of messages that are waiting for responses from + * the DTE, and complete or retry any that have timed out. */ + list_for_each_entry_safe(cmd, temp, &wc->waiting_for_response_list, node) { + if (time_after(jiffies, cmd->timeout)) { + if (++cmd->retries > MAX_RETRIES) { + if (!(cmd->flags & TX_COMPLETE)) { + set_bit(DTE_SHUTDOWN, &wc->flags); + spin_unlock(&wc->cmd_list_lock); + wctc4xxp_stop_dma(wc); + DTE_PRINTK(ERR, "Board malfunctioning. Halting operation.\n"); + return; + } + /* ERROR: We've retried the command and haven't + * received the ACK or the response. */ + cmd->flags |= DTE_CMD_TIMEOUT; + list_del_init(&cmd->node); + complete(&cmd->complete); + } else if (cmd->flags & TX_COMPLETE) { + /* Move this to the local list because we're + * going to resend it once we free the locks */ + list_move_tail(&cmd->node, &cmds_to_retry); + } else { + /* The command is still sitting on the tx + * descriptor ring. We don't want to move it + * off any lists, lets just reset the timeout + * and tell the hardware to look for another + * command . */ + DTE_PRINTK(WARNING, "Retrying command that was " \ + "still on descriptor list.\n"); + cmd->timeout = jiffies + HZ/4; + wctc4xxp_transmit_demand_poll(wc); + } + } + } + spin_unlock(&wc->cmd_list_lock); + wctc4xxp_send_commands(wc, &cmds_to_retry); +} + +/** + * Insert an struct wcdte on the global list in sorted order + * + */ +static int __devinit +wctc4xxp_add_to_device_list(struct wcdte *wc) +{ + struct wcdte *cur; + int pos = 0; + INIT_LIST_HEAD(&wc->node); + spin_lock(&wctc4xxp_list_lock); + list_for_each_entry(cur, &wctc4xxp_list, node) { + if (cur->pos != pos) { + /* Add the new entry before the one here */ + list_add_tail(&wc->node, &wctc4xxp_list); + break; + } + else { + ++pos; + } + } + spin_unlock(&wctc4xxp_list_lock); + return pos; +} + +struct wctc4xxp_desc { + const char *short_name; + const char *long_name; + int flags; +}; + +static struct wctc4xxp_desc wctc400p = { + .short_name = "tc400b", + .long_name = "Wildcard TC400P+TC400M", + .flags = 0, +}; + +static struct wctc4xxp_desc wctce400 = { + .short_name = "tce400", + .long_name = "Wildcard TCE400+TC400M", + .flags = 0, +}; + +static int __devinit +wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int res, reg, position_on_list; + struct wcdte *wc = NULL; + struct wctc4xxp_desc *d = (struct wctc4xxp_desc *)ent->driver_data; + unsigned char g729_numchannels, g723_numchannels, min_numchannels; + unsigned char wctc4xxp_firmware_ver, wctc4xxp_firmware_ver_minor; + unsigned int complexfmts; struct firmware embedded_firmware; const struct firmware *firmware = &embedded_firmware; #if !defined(HOTPLUG_FIRMWARE) - extern void _binary_zaptel_fw_tc400m_bin_size; - extern u8 _binary_zaptel_fw_tc400m_bin_start[]; + extern void _binary_zt_fw_tc400m_bin_size; + extern u8 _binary_zt_fw_tc400m_bin_start[]; #else static const char tc400m_firmware[] = "zaptel-fw-tc400m.bin"; #endif - if (!initd_ifaces) { - memset((void *)ifaces,0,(sizeof(struct wcdte *))*WC_MAX_IFACES); - initd_ifaces=1; + /* ------------------------------------------------------------------ + * Setup the pure software constructs internal to this driver. + * --------------------------------------------------------------- */ + + if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { + return -ENOMEM; } - for (x=0;x= WC_MAX_IFACES) { - printk("wcdte: Too many interfaces\n"); + memset(wc, 0, sizeof(*wc)); + + position_on_list = wctc4xxp_add_to_device_list(wc); + snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d", + d->short_name, position_on_list); + wc->iobase = pci_resource_start(pdev, 0); + wc->pdev = pdev; + wc->pos = position_on_list; + wc->variety = d->long_name; + + init_MUTEX(&wc->chansem); + spin_lock_init(&wc->reglock); + spin_lock_init(&wc->cmd_list_lock); + INIT_LIST_HEAD(&wc->cmd_list); + INIT_LIST_HEAD(&wc->waiting_for_response_list); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&wc->deferred_work, deferred_work_func, wc); +#else + INIT_WORK(&wc->deferred_work, deferred_work_func); +#endif + DTE_PRINTK(INFO, "Attached to device at %s.\n", pci_name(wc->pdev)); + + /* Keep track of whether we need to free the region */ + if (!request_region(wc->iobase, 0xff, wc->board_name)) { + /* \todo put in error message. */ + DTE_PRINTK(WARNING, + "Failed to reserve the I/O ports for this device.\n"); return -EIO; } - if (pci_enable_device(pdev)) { - res = -EIO; - } else { + init_waitqueue_head(&wc->waitq); - wc = vmalloc(sizeof(struct wcdte)); - if (wc) { - ifaces[x] = wc; - memset(wc, 0, sizeof(struct wcdte)); - spin_lock_init(&wc->reglock); - sema_init(&wc->chansem, 1); - sema_init(&wc->cmdqsem, 1); - wc->cards = NUM_CARDS; - wc->iobase = pci_resource_start(pdev, 0); - wc->dev = pdev; - wc->pos = x; - wc->variety = d->name; - - wc->tdbl = 0; - wc->rdbl = 0; - wc->rcvflags = 0; - wc->last_seqno = 999; - wc->last_command_sent = 0; - wc->last_rcommand = 0; - wc->last_rparm1 = 0; - wc->cmdq_wndx = 0; - wc->cmdq_rndx = 0; - wc->seq_num = 6; - wc->timeout = 1 * HZ; /* 1 sec */ - wc->dsp_crashed = 0; - wc->dumping = 0; - wc->ztsnd_rtx = 0; - wc->ztsnd_0010_rtx = 0; - - /* Keep track of whether we need to free the region */ - if (request_region(wc->iobase, 0xff, "wcdte")) - wc->freeregion = 1; - - /* Allocate enought memory for all TX buffers, RX buffers, and descriptors */ - wc->writechunk = (int *)pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma); - if (!wc->writechunk) { - printk("wcdte error: Unable to allocate DMA-able memory\n"); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - return -ENOMEM; - } + if (pci_set_dma_mask(wc->pdev, DMA_32BIT_MASK)) { + release_region(wc->iobase, 0xff); + DTE_PRINTK(WARNING, "No suitable DMA available.\n"); + return -EIO; + } - wc->readchunk = wc->writechunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */ - wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */ + if (!(wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL))) { + res = -ENOMEM; + goto error_exit_swinit; + } - wc->descripchunk = wc->readchunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */ - wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */ + if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd, + 0xe0800000, + DMA_TO_DEVICE))) { + goto error_exit_swinit; + } - /* Initialize Write/Buffers to all blank data */ - memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2); - memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2); + if (!(wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL))) { + res = -ENOMEM; + goto error_exit_swinit; + } - init_waitqueue_head(&wc->regq); - - /* Initialize the work queue */ - wc->dte_wq = create_singlethread_workqueue("tc400b"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) - INIT_WORK(&wc->dte_work, dte_wque_run); -#else - INIT_WORK(&wc->dte_work, dte_wque_run, wc); -#endif + if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0, + DMA_FROM_DEVICE))) { + goto error_exit_swinit; + } #if defined(HOTPLUG_FIRMWARE) - if ((request_firmware(&firmware, tc400m_firmware, &wc->dev->dev) != 0) || - !firmware) { - printk("TC400M: firmware %s not available from userspace\n", tc400m_firmware); - return -EIO; - } + if ((res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev)) || + !firmware) { + DTE_PRINTK(ERR, "Firmware %s not available from userspace. (%d)\n", tc400m_firmware, res); + goto error_exit_swinit; + } #else - embedded_firmware.data = _binary_zaptel_fw_tc400m_bin_start; - embedded_firmware.size = (size_t) &_binary_zaptel_fw_tc400m_bin_size; + embedded_firmware.data = _binary_zt_fw_tc400m_bin_start; + embedded_firmware.size = (size_t) &_binary_zt_fw_tc400m_bin_size; #endif - dte_firmware_ver = firmware->data[0]; - dte_firmware_ver_minor = firmware->data[16]; - g729_numchannels = firmware->data[1]; - g723_numchannels = firmware->data[2]; - - if (g723_numchannels < g729_numchannels) - min_numchannels = g723_numchannels; - else - min_numchannels = g729_numchannels; - - /* Setup Encoders and Decoders */ - - if (!mode || strlen(mode) < 4) { - sprintf(wc->complexname, "G.729a / G.723.1"); - complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1; - wc->numchannels = min_numchannels; - } else if (mode[3] == '9') { /* "G.729" */ - sprintf(wc->complexname, "G.729a"); - complexfmts = ZT_FORMAT_G729A; - wc->numchannels = g729_numchannels; - } else if (mode[3] == '3') { /* "G.723.1" */ - sprintf(wc->complexname, "G.723.1"); - complexfmts = ZT_FORMAT_G723_1; - wc->numchannels = g723_numchannels; - } else { - sprintf(wc->complexname, "G.729a / G.723.1"); - complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1; - wc->numchannels = min_numchannels; - } - - uencode = zt_transcoder_alloc(wc->numchannels); - udecode = zt_transcoder_alloc(wc->numchannels); - encoders = vmalloc(sizeof(struct dte_state) * wc->numchannels); - decoders = vmalloc(sizeof(struct dte_state) * wc->numchannels); - memset(encoders, 0, sizeof(struct dte_state) * wc->numchannels); - memset(decoders, 0, sizeof(struct dte_state) * wc->numchannels); - if (!uencode || !udecode || !encoders || !decoders) { - if (uencode) - zt_transcoder_free(uencode); - if (udecode) - zt_transcoder_free(udecode); - if (encoders) - vfree(encoders); - if (decoders) - vfree(decoders); - return -ENOMEM; - } - sprintf(udecode->name, "DTE Decoder"); - sprintf(uencode->name, "DTE Encoder"); - - udecode->srcfmts = uencode->dstfmts = complexfmts; - udecode->dstfmts = uencode->srcfmts = ZT_FORMAT_ULAW | ZT_FORMAT_ALAW; - - udecode->operation = uencode->operation = dte_operation; - - for (x=0;xnumchannels;x++) { - dte_init_state(encoders + x, 1, x, wc); - encoders[x].encoder = 1; - decoders[x].encoder = 0; - dte_init_state(decoders + x, 0, x, wc); - uencode->channels[x].pvt = encoders + x; - udecode->channels[x].pvt = decoders + x; - } - - wc->uencode = uencode; - wc->udecode = udecode; - - zt_transcoder_register(uencode); - zt_transcoder_register(udecode); + wctc4xxp_firmware_ver = firmware->data[0]; + wctc4xxp_firmware_ver_minor = firmware->data[16]; + g729_numchannels = firmware->data[1]; + g723_numchannels = firmware->data[2]; + + min_numchannels = min(g723_numchannels, g729_numchannels); + + if (!mode || strlen(mode) < 4) { + sprintf(wc->complexname, "G.729a / G.723.1"); + complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1; + wc->numchannels = min_numchannels; + } else if (mode[3] == '9') { /* "G.729" */ + sprintf(wc->complexname, "G.729a"); + complexfmts = ZT_FORMAT_G729A; + wc->numchannels = g729_numchannels; + } else if (mode[3] == '3') { /* "G.723.1" */ + sprintf(wc->complexname, "G.723.1"); + complexfmts = ZT_FORMAT_G723_1; + wc->numchannels = g723_numchannels; + } else { + sprintf(wc->complexname, "G.729a / G.723.1"); + complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1; + wc->numchannels = min_numchannels; + } - printk("Zaptel DTE (%s) Transcoder support LOADED (firm ver = %d.%d)\n", wc->complexname, dte_firmware_ver, dte_firmware_ver_minor); + if ((res = initialize_encoders(wc, complexfmts))) { + goto error_exit_swinit; + } + if ((res = initialize_decoders(wc, complexfmts))) { + goto error_exit_swinit; + } + + if (DTE_DEBUG_NETWORK_IF & debug) { + if ((res = wctc4xxp_net_register(wc))) { + goto error_exit_swinit; + } + } + setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc); - /* Enable bus mastering */ - pci_set_master(pdev); + /* ------------------------------------------------------------------ + * Load the firmware and start the DTE. + * --------------------------------------------------------------- */ - /* Keep track of which device we are */ - pci_set_drvdata(pdev, wc); + if ((res = pci_enable_device(pdev))) { + DTE_PRINTK(ERR, "Failed to enable device.\n"); + goto error_exit_swinit;; + } + pci_set_master(pdev); + pci_set_drvdata(pdev, wc); + if ((res = request_irq(pdev->irq, wctc4xxp_interrupt, ZAP_IRQ_SHARED, wc->board_name, wc))) { + DTE_PRINTK(ERR, "Unable to request IRQ %d\n", pdev->irq); + if (firmware != &embedded_firmware) { + release_firmware(firmware); + } + goto error_exit_hwinit; + } + if ((res = wctc4xxp_hardware_init(wc))) { + if (firmware != &embedded_firmware) { + release_firmware(firmware); + } + goto error_exit_hwinit; + } + wctc4xxp_enable_interrupts(wc); + wctc4xxp_start_dma(wc); + res = wctc4xxp_boot_processor(wc, firmware); + if (firmware != &embedded_firmware) { + release_firmware(firmware); + } + if (res) { + goto error_exit_hwinit; + } - if (request_irq(pdev->irq, wcdte_interrupt, ZAP_IRQ_SHARED, "tc400b", wc)) { - printk("wcdte error: Unable to request IRQ %d\n", pdev->irq); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - vfree(wc); - return -EIO; - } + if ((res = wctc4xxp_setup_channels(wc))) { + goto error_exit_hwinit; + } + /* \todo Read firmware version directly from tc400b.*/ + DTE_PRINTK(INFO, "(%s) Transcoder support LOADED " \ + "(firm ver = %d.%d)\n", wc->complexname, wctc4xxp_firmware_ver, + wctc4xxp_firmware_ver_minor); - if (wcdte_hardware_init(wc)) { - /* Set Reset Low */ - wcdte_stop_dma(wc); - /* Free Resources */ - free_irq(pdev->irq, wc); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - vfree(wc); - return -EIO; + reg = wctc4xxp_getctl(wc, 0x00fc); - } + DTE_DEBUG(DTE_DEBUG_GENERAL, + "debug: (post-boot) Reg fc is %08x\n", reg); + + DTE_PRINTK(INFO, "Installed a Wildcard TC: %s \n", wc->variety); + DTE_DEBUG(DTE_DEBUG_GENERAL, "Operating in DEBUG mode.\n"); + zt_transcoder_register(wc->uencode); + zt_transcoder_register(wc->udecode); - /* Enable interrupts */ - wcdte_enable_interrupts(wc); - - /* Start DMA */ - wcdte_start_dma(wc); - - if (wcdte_boot_processor(wc,firmware,1)) { - if (firmware != &embedded_firmware) - release_firmware(firmware); - - /* Set Reset Low */ - wcdte_stop_dma(wc); - /* Free Resources */ - free_irq(pdev->irq, wc); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - vfree(wc); - return -EIO; - } - if (firmware != &embedded_firmware) - release_firmware(firmware); - - if (wcdte_setup_channels(wc)) { - /* Set Reset Low */ - wcdte_stop_dma(wc); - /* Free Resources */ - free_irq(pdev->irq, wc); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - vfree(wc); - return -EIO; - } + return 0; - reg = wcdte_getctl(wc, 0x00fc); - if (debug) - printk("wcdte debug: (post-boot) Reg fc is %08x\n", reg); - - printk("Found and successfully installed a Wildcard TC: %s \n", wc->variety); - if (debug) { - printk("TC400B operating in DEBUG mode\n"); - printk("debug_des = %d, debug_des_cnt = %d, force_alert = %d,\n debug_notimeout = %d, debug_packets = %d\n", - debug_des, debug_des_cnt, force_alert, debug_notimeout, debug_packets); - } - res = 0; - } else - res = -ENOMEM; +error_exit_hwinit: + wctc4xxp_stop_dma(wc); + wctc4xxp_cleanup_command_list(wc); + free_irq(pdev->irq, wc); + pci_set_drvdata(pdev, NULL); +error_exit_swinit: + wctc4xxp_net_unregister(wc); + if (wc->encoders) kfree(wc->encoders); + if (wc->decoders) kfree(wc->decoders); + if (wc->uencode) zt_transcoder_free(wc->uencode); + if (wc->udecode) zt_transcoder_free(wc->udecode); + if (wc->txd) { + if (wc->txd->desc) { + wctc4xxp_cleanup_descriptor_ring(wc->txd); + } + kfree(wc->txd); } - return res; + if (wc->rxd) { + if (wc->rxd && wc->rxd->desc) { + wctc4xxp_cleanup_descriptor_ring(wc->rxd); + } + kfree(wc->rxd); + } + release_region(wc->iobase, 0xff); + spin_lock(&wctc4xxp_list_lock); + list_del(&wc->node); + spin_unlock(&wctc4xxp_list_lock); + kfree(wc); + return res; } -static void wcdte_release(struct wcdte *wc) +static void wctc4xxp_cleanup_channels(struct wcdte *wc) { - if (wc->freeregion) - release_region(wc->iobase, 0xff); - vfree(wc); + int i; + struct zt_transcoder_channel *dtc_en, *dtc_de; + struct channel_pvt *cpvt; + + for(i = 0; i < wc->numchannels; i++) { + dtc_en = &(wc->uencode->channels[i]); + cpvt = dtc_en->pvt; + wctc4xxp_cleanup_channel_private(wc, cpvt); + + dtc_de = &(wc->udecode->channels[i]); + cpvt = dtc_de->pvt; + wctc4xxp_cleanup_channel_private(wc, cpvt); + } } -static void __devexit wcdte_remove_one(struct pci_dev *pdev) +static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev) { int i; struct wcdte *wc = pci_get_drvdata(pdev); - struct zt_transcoder_channel *ztc_en, *ztc_de; - struct dte_state *st_en, *st_de; - - if (wc) { - if (debug) - { - printk("wcdte debug: wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx); - printk("wcdte debug: wc->ztsnd_0010_rtx = %d\n", wc->ztsnd_0010_rtx); - - for(i = 0; i < wc->numchannels; i++) - { - ztc_en = &(wc->uencode->channels[i]); - st_en = ztc_en->pvt; - - ztc_de = &(wc->udecode->channels[i]); - st_de = ztc_de->pvt; - - printk("wcdte debug: en[%d] snt = %d, rcv = %d [%d]\n", i, st_en->packets_sent, st_en->packets_received, st_en->packets_sent - st_en->packets_received); - printk("wcdte debug: de[%d] snt = %d, rcv = %d [%d]\n", i, st_de->packets_sent, st_de->packets_received, st_de->packets_sent - st_de->packets_received); - } + struct zt_transcoder_channel *dtc_en, *dtc_de; + struct channel_pvt *cpvt; + + if (!wc) { + /* \todo print warning message here. */ + return; + } + + spin_lock(&wctc4xxp_list_lock); + list_del(&wc->node); + spin_unlock(&wctc4xxp_list_lock); + + set_bit(DTE_SHUTDOWN, &wc->flags); + if (del_timer_sync(&wc->watchdog)) { + /* Just delete the timer twice in case the timer had already + * checked DTE_SHUTDOWN and rescheduled itself the first time. + */ + del_timer_sync(&wc->watchdog); + } + + wctc4xxp_net_unregister(wc); + + if (debug) { + for(i = 0; i < wc->numchannels; i++) { + dtc_en = &(wc->uencode->channels[i]); + cpvt = dtc_en->pvt; + DTE_DEBUG(DTE_DEBUG_GENERAL, + "encoder[%d] snt = %d, rcv = %d [%d]\n", i, + atomic_read(&cpvt->stats.packets_sent), + atomic_read(&cpvt->stats.packets_received), + atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received)); + + dtc_de = &(wc->udecode->channels[i]); + cpvt = dtc_de->pvt; + DTE_DEBUG(DTE_DEBUG_GENERAL, + "decoder[%d] snt = %d, rcv = %d [%d]\n", i, + atomic_read(&cpvt->stats.packets_sent), + atomic_read(&cpvt->stats.packets_received), + atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received)); } + } + + /* Stop any DMA */ + wctc4xxp_stop_dma(wc); - zt_transcoder_unregister(wc->udecode); - zt_transcoder_unregister(wc->uencode); - zt_transcoder_free(wc->uencode); - zt_transcoder_free(wc->udecode); - vfree(wc->uencode->channels[0].pvt); - vfree(wc->udecode->channels[0].pvt); + /* In case hardware is still there */ + wctc4xxp_disable_interrupts(wc); - /* Stop any DMA */ - wcdte_stop_dma(wc); + free_irq(pdev->irq, wc); - /* In case hardware is still there */ - wcdte_disable_interrupts(wc); + /* There isn't anything that would run in the workqueue that will wait + * on an interrupt. */ - /* Kill workqueue */ - destroy_workqueue(wc->dte_wq); - - /* Immediately free resources */ - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - free_irq(pdev->irq, wc); + zt_transcoder_unregister(wc->udecode); + zt_transcoder_unregister(wc->uencode); - /* Release span, possibly delayed */ - wcdte_release(wc); + /* Free Resources */ + release_region(wc->iobase, 0xff); + spin_lock_bh(&wc->cmd_list_lock); + if (wc->txd) { + if (wc->txd->desc) wctc4xxp_cleanup_descriptor_ring(wc->txd); + kfree(wc->txd); + } + if (wc->rxd) { + if (wc->rxd && wc->rxd->desc) wctc4xxp_cleanup_descriptor_ring(wc->rxd); + kfree(wc->rxd); } + spin_unlock_bh(&wc->cmd_list_lock); + wctc4xxp_cleanup_command_list(wc); + wctc4xxp_cleanup_channels(wc); + + pci_set_drvdata(pdev, NULL); + + zt_transcoder_free(wc->uencode); + zt_transcoder_free(wc->udecode); + kfree(wc->encoders); + kfree(wc->decoders); + kfree(wc); } -static struct pci_device_id wcdte_pci_tbl[] = { -#ifndef USE_TEST_HW +static struct pci_device_id wctc4xxp_pci_tbl[] = { { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */ { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */ -#else - { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* reference board */ -#endif { 0 } }; -MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl); +MODULE_DEVICE_TABLE(pci, wctc4xxp_pci_tbl); -static struct pci_driver wcdte_driver = { +static struct pci_driver wctc4xxp_driver = { name: "wctc4xxp", - probe: wcdte_init_one, - remove: __devexit_p(wcdte_remove_one), + probe: wctc4xxp_init_one, + remove: __devexit_p(wctc4xxp_remove_one), suspend: NULL, resume: NULL, - id_table: wcdte_pci_tbl, + id_table: wctc4xxp_pci_tbl, }; -int ztdte_init(void) +int __init wctc4xxp_init(void) { int res; - - res = zap_pci_module(&wcdte_driver); +# ifndef CONFIG_WCDTE_NETWORK_IF + if (debug & (DTE_DEBUG_NETWORK_IF|DTE_DEBUG_NETWORK_EARLY)) { + printk(KERN_WARNING "%s: The Network interface was not compiled into the driver.\n", THIS_MODULE->name); + debug &= ~(DTE_DEBUG_NETWORK_IF|DTE_DEBUG_NETWORK_EARLY); + } +# endif + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); +# else + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, + SLAB_HWCACHE_ALIGN, NULL); +# endif + + if (!cmd_cache) { + return -ENOMEM; + } + spin_lock_init(&wctc4xxp_list_lock); + INIT_LIST_HEAD(&wctc4xxp_list); + res = zap_pci_module(&wctc4xxp_driver); if (res) return -ENODEV; return 0; } -void ztdte_cleanup(void) +void __exit wctc4xxp_cleanup(void) { - pci_unregister_driver(&wcdte_driver); + WARN_ON(!list_empty(&wctc4xxp_list)); + pci_unregister_driver(&wctc4xxp_driver); + kmem_cache_destroy(cmd_cache); } module_param(debug, int, S_IRUGO | S_IWUSR); -module_param(debug_des, int, S_IRUGO | S_IWUSR); -module_param(debug_des_cnt, int, S_IRUGO | S_IWUSR); -module_param(debug_notimeout, int, S_IRUGO | S_IWUSR); -module_param(force_alert, int, S_IRUGO | S_IWUSR); -module_param(mode, charp, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver"); -MODULE_AUTHOR("John Sloan "); +MODULE_AUTHOR("Digium Incorporated "); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif -module_init(ztdte_init); -module_exit(ztdte_cleanup); +module_init(wctc4xxp_init); +module_exit(wctc4xxp_cleanup); diff --git a/kernel/wctc4xxp/codec_test.c b/kernel/wctc4xxp/codec_test.c deleted file mode 100644 index a476212..0000000 --- a/kernel/wctc4xxp/codec_test.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Wilcard TC400B Digium Transcoder Engine Interface Driver for Zapata Telephony interface test tool. - * - * Written by Matt O'Gorman - * - * Copyright (C) 2006-2007, Digium, Inc. - * - * All rights reserved. - * - */ - -/* - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2 as published by the - * Free Software Foundation. See the LICENSE file included with - * this program for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef STANDALONE_ZAPATA -#include "zaptel.h" -#else -#include -#endif - -#define MAX_CARDS_TO_TEST 6 -#define MAX_CHANNELS_PER_CARD 96 - -#define AST_FORMAT_ULAW (1 << 2) -#define AST_FORMAT_G729A (1 << 8) - -#define AST_FRIENDLY_OFFSET 64 - -static int debug = 0; - -static unsigned char ulaw_slin_ex[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char g729a_expected[] = { - 0xE9, 0x88, 0x4C, 0xA0, 0x00, 0xFA, 0xDD, 0xA2, 0x06, 0x2D, - 0x69, 0x88, 0x00, 0x60, 0x68, 0xD5, 0x9E, 0x20, 0x80, 0x50 -}; - - -struct format_map { - unsigned int map[32][32]; -}; - - -struct tcpvt { - int fd; - int fake; - int inuse; - struct zt_transcode_header *hdr; -// struct ast_frame f; -}; - -struct tctest_info { - int numcards; - int numchans[MAX_CARDS_TO_TEST]; - int total_chans; - int errors; - int overcnt_error; /* Too many cards found */ - int undercnt_error; /* Too few cards found */ - int timeout_error[MAX_CARDS_TO_TEST]; - int data_error[MAX_CARDS_TO_TEST]; - int numcards_werrors; -}; - - -static int find_transcoders(struct tctest_info *tctest_info) -{ - struct zt_transcode_info info = { 0, }; - int fd, res; - - if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) { - printf("Warning: No Zaptel transcoder support!\n"); - return 0; - } - - tctest_info->total_chans = 0; - info.op = ZT_TCOP_GETINFO; - for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) { - if (debug) - printf("Found transcoder %d, '%s' with %d channels.\n", info.tcnum, info.name, info.numchannels); - if ((info.tcnum % 2) == 0) - { - tctest_info->numchans[info.tcnum/2] = info.numchannels; - tctest_info->total_chans += info.numchannels; - } - } - tctest_info->numcards = info.tcnum / 2; - - close(fd); - if (!info.tcnum) - printf("No hardware transcoders found.\n"); - return 0; -} - - -static int open_transcoder(struct tcpvt *ztp, int dest, int source) -{ - int fd; - unsigned int x = ZT_TCOP_ALLOCATE; - struct zt_transcode_header *hdr; - int flags; - - if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) - return -1; - flags = fcntl(fd, F_GETFL); - if (flags > - 1) { - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) - printf("Could not set non-block mode!\n"); - } - - if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { - printf("Memory Map failed for transcoding (%s)\n", strerror(errno)); - close(fd); - - return -1; - } - - if (hdr->magic != ZT_TRANSCODE_MAGIC) { - printf("Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic); - munmap(hdr, sizeof(*hdr)); - close(fd); - - return -1; - } - - hdr->srcfmt = source; - hdr->dstfmt = dest; - - if (ioctl(fd, ZT_TRANSCODE_OP, &x)) { - printf("Unable to attach transcoder: %s\n", strerror(errno)); - munmap(hdr, sizeof(*hdr)); - close(fd); - - return -1; - } - - ztp->fd = fd; - ztp->hdr = hdr; - - return 0; -} - - -static void close_transcoder(struct tcpvt *ztp) -{ - unsigned int x; - - x = ZT_TCOP_RELEASE; - if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) - printf("Failed to release transcoder channel: %s\n", strerror(errno)); - - munmap(ztp->hdr, sizeof(*ztp->hdr)); - close(ztp->fd); -} - - -static int encode_packet(struct tcpvt *ztp, unsigned char *packet_in, unsigned char *packet_out) -{ - struct zt_transcode_header *hdr = ztp->hdr; - unsigned int x; - - hdr->srcoffset = 0; - - memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, packet_in, 160); - hdr->srclen += 160; - - - hdr->dstoffset = AST_FRIENDLY_OFFSET; - x = ZT_TCOP_TRANSCODE; - if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) - printf("Failed to transcode: %s\n", strerror(errno)); - - usleep(20000); - if (hdr->dstlen) - { - memcpy(packet_out, hdr->dstdata + hdr->dstoffset, hdr->dstlen); - return 0; - } - else - return -1; -} - - -static void print_failed() -{ - printf("______ ___ _____ _ _____ ______\n"); - printf("| ___| / _ \\ |_ _| | | | ___| | _ \\\n"); - printf("| |_ / /_\\ \\ | | | | | |__ | | | |\n"); - printf("| _| | _ | | | | | | __| | | | |\n"); - printf("| | | | | | _| |_ | |____ | |___ | |/ /\n"); - printf("\\_| \\_| |_/ \\___/ \\_____/ \\____/ |___/ \n"); -} - - -int main(int argc, char *argv[]) -{ - int arg1, arg2, i, j, card_testing, chan_testing; - struct tcpvt ztp[MAX_CHANNELS_PER_CARD * MAX_CARDS_TO_TEST]; - unsigned char packet_out[200]; - struct tctest_info tctest_info; - - memset(&tctest_info, 0, sizeof(tctest_info)); - - if ((argc < 2) || (argc > 3)) - { - printf("codec_test requires one argument.\n"); - printf(" arg1 = number of cards to test\n"); - return -1; - } - - if (argc == 2) - sscanf(argv[1], "%d", &arg1); - else if (argc == 3) - { - sscanf(argv[1], "%d %d", &arg1, &arg2); - debug = arg2; - } - - printf("Beginning test of %d TC400B cards\n", arg1); - - - /* Search for TC400Bs */ - find_transcoders(&tctest_info); - - if (tctest_info.numcards > arg1) - { - tctest_info.errors++; - tctest_info.overcnt_error = 1; - } - if (tctest_info.numcards < arg1) - { - tctest_info.errors++; - tctest_info.undercnt_error = 1; - } - - if (tctest_info.errors == 0) - { - /* Begin testing transcoder channels */ - for (card_testing = 0; card_testing < tctest_info.numcards; card_testing++) - { - tctest_info.data_error[card_testing] = 0; - tctest_info.timeout_error[card_testing] = 0; - for (chan_testing = 0; chan_testing < tctest_info.numchans[card_testing]; chan_testing++) - { - i = chan_testing; - for(j = 0; j < card_testing; j++) - i += tctest_info.numchans[j]; - - open_transcoder(&ztp[i], AST_FORMAT_G729A, AST_FORMAT_ULAW); - - if ((tctest_info.timeout_error[card_testing] = encode_packet(&ztp[i], ulaw_slin_ex, packet_out) == -1)) - tctest_info.errors++; - - if (memcmp(g729a_expected, packet_out, 20) != 0) - { - tctest_info.errors++; - tctest_info.data_error[card_testing] += 1; - } - } - if ( (tctest_info.data_error[card_testing]) || (tctest_info.timeout_error[card_testing]) ) - tctest_info.numcards_werrors++; - } - - for (i = 0; i < tctest_info.total_chans; i++) - close_transcoder(&ztp[i]); - } - - if (debug) - { - printf("\n\n"); - printf("tctest_info.errors = %d\n", tctest_info.errors); - printf("tctest_info.overcnt_error = %d\n", tctest_info.overcnt_error); - printf("tctest_info.undercnt_error = %d\n", tctest_info.undercnt_error); - printf("tctest_info.numcards_werrors = %d\n", tctest_info.numcards_werrors); - - for (i = 0; i < tctest_info.numcards; i++) - { - printf("tctest_info.data_error[%d] = %d\n", i, tctest_info.data_error[i]); - printf("tctest_info.timeout_error[%d] = %d\n", i, tctest_info.timeout_error[i]); - } - } - - if (tctest_info.errors) - { - printf("\n\n\n"); - if (tctest_info.numcards_werrors) - printf("%d of %d cards\n", tctest_info.numcards_werrors, tctest_info.numcards); - print_failed(); - if (tctest_info.overcnt_error) - printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1); - if (tctest_info.undercnt_error) - printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1); - printf("\n\n\n"); - } - else - printf("%d of %d cards PASSED\n", tctest_info.numcards - tctest_info.numcards_werrors, tctest_info.numcards); - - return 0; -} diff --git a/kernel/zaptel-base.c b/kernel/zaptel-base.c index 53b6f15..deeb01c 100644 --- a/kernel/zaptel-base.c +++ b/kernel/zaptel-base.c @@ -2579,30 +2579,29 @@ static void zt_free_pseudo(struct zt_chan *pseudo) static int zt_open(struct inode *inode, struct file *file) { int unit = UNIT(file); - int ret = -ENXIO; + struct zt_chan *chan; /* Minor 0: Special "control" descriptor */ if (!unit) return zt_ctl_open(inode, file); if (unit == 250) { if (!zt_transcode_fops) - request_module("zttranscode"); - if (zt_transcode_fops && zt_transcode_fops->open) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - if (zt_transcode_fops->owner) { - __MOD_INC_USE_COUNT (zt_transcode_fops->owner); -#else - if (try_module_get(zt_transcode_fops->owner)) { -#endif - ret = zt_transcode_fops->open(inode, file); - if (ret) + if (request_module("zttranscode")) { + return -ENXIO; + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - __MOD_DEC_USE_COUNT (zt_transcode_fops->owner); + __MOD_INC_USE_COUNT (zt_transcode_fops->owner); #else - module_put(zt_transcode_fops->owner); + if (!try_module_get(zt_transcode_fops->owner)) { + return -ENXIO; + } #endif - } - return ret; + if (zt_transcode_fops && zt_transcode_fops->open) { + return zt_transcode_fops->open(inode, file); + } else { + /* zttranscode module should have exported a + * file_operations table. */ + WARN_ON(1); } return -ENXIO; } @@ -3124,14 +3123,11 @@ static int zt_release(struct inode *inode, struct file *file) return zt_timer_release(inode, file); } if (unit == 250) { - res = zt_transcode_fops->release(inode, file); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - if (zt_transcode_fops->owner) - __MOD_DEC_USE_COUNT (zt_transcode_fops->owner); -#else - module_put(zt_transcode_fops->owner); -#endif - return res; + /* We should not be here because the zttranscode.ko module + * should have updated the file_operations for this file + * handle when the file was opened. */ + WARN_ON(1); + return -EFAULT; } if (unit == 254) { chan = file->private_data; @@ -5147,8 +5143,12 @@ static int zt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if (!unit) return zt_ctl_ioctl(inode, file, cmd, data); - if (unit == 250) - return zt_transcode_fops->ioctl(inode, file, cmd, data); + if (unit == 250) { + /* zttranscode should have updated the file_operations on + * this file object on open, so we shouldn't be here. */ + WARN_ON(1); + return -EFAULT; + } if (unit == 253) { timer = file->private_data; diff --git a/kernel/zaptel.h b/kernel/zaptel.h index 157747a..fd57755 100644 --- a/kernel/zaptel.h +++ b/kernel/zaptel.h @@ -777,8 +777,30 @@ struct zt_hwgain{ /* * Transcoder operations */ + +/* ZT_TRANSCODE_OP is an older interface that is deprecated and no longer + * supported. + */ #define ZT_TRANSCODE_OP _IOWR(ZT_CODE, 93, int) +/* Transcoder related definitions */ + +struct zt_transcoder_formats { + __u32 srcfmt; + __u32 dstfmt; +}; +struct zt_transcoder_info { + __u32 tcnum; + char name[80]; + __u32 numchannels; + __u32 dstfmts; + __u32 srcfmts; +}; + +#define ZT_TC_CODE 'T' +#define ZT_TC_ALLOCATE _IOW(ZT_TC_CODE, 1, struct zt_transcoder_formats) +#define ZT_TC_GETINFO _IOWR(ZT_TC_CODE, 2, struct zt_transcoder_info) + /* * VoiceMail Waiting Indication (WMWI) -- implemented by low-level driver. * Value: number of waiting messages (hence 0: switch messages off). @@ -900,57 +922,6 @@ enum { #define ZT_TONEDETECT_ON (1 << 0) /* Detect tones */ #define ZT_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */ -#define ZT_TRANSCODE_MAGIC 0x74a9c0de - -/* Operations */ -#define ZT_TCOP_ALLOCATE 1 /* Allocate/reset DTE channel */ -#define ZT_TCOP_TRANSCODE 2 /* Begin transcoding a block */ -#define ZT_TCOP_GETINFO 3 /* Get information (use zt_transcode_info) */ -#define ZT_TCOP_RELEASE 4 /* Release DTE channel */ -#define ZT_TCOP_TEST 5 /* test DTE device */ -typedef struct zt_transcode_info { - unsigned int op; - unsigned int tcnum; - char name[80]; - int numchannels; - unsigned int srcfmts; - unsigned int dstfmts; -} ZT_TRANSCODE_INFO; - -#define ZT_TCCONF_USETS (1 << 0) /* Use/update timestamp field */ -#define ZT_TCCONF_USESEQ (1 << 1) /* Use/update seqno field */ - -#define ZT_TCSTAT_DSTRDY (1 << 0) /* Destination data is ready */ -#define ZT_TCSTAT_DSTBUSY (1 << 1) /* Destination data is outstanding */ - -#define __ZT_TRANSCODE_BUFSIZ 16384 -#define ZT_TRANSCODE_HDRLEN 256 -#define ZT_TRANSCODE_BUFSIZ ((__ZT_TRANSCODE_BUFSIZ) - (ZT_TRANSCODE_HDRLEN)) -#define ZT_TRANSCODE_DSTOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN) -#define ZT_TRANSCODE_SRCOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN) - -typedef struct zt_transcode_header { - unsigned int srcfmt; /* See formats.h -- use TCOP_RESET when you change */ - unsigned int srcoffset; /* In bytes -- written by user */ - unsigned int srclen; /* In bytes -- written by user */ - unsigned int srctimestamp; /* In samples -- written by user (only used if ZT_TCCONF_USETS is set) */ - unsigned int srcseqno; /* In units -- written by user (only used if ZT_TCCONF_USESEQ is set) */ - - unsigned int dstfmt; /* See formats.h -- use TCOP_RESET when you change */ - unsigned int dstoffset; /* In bytes -- written by user */ - unsigned int dsttimestamp; /* In samples -- read by user */ - unsigned int dstseqno; /* In units -- read by user (only used if ZT_TCCONF_USESEQ is set) */ - unsigned int dstlen; /* In bytes -- read by user */ - unsigned int dstsamples; /* In timestamp units -- read by user */ - - unsigned int magic; /* Magic value -- ZT_TRANSCODE_MAGIC, read by user */ - unsigned int config; /* Read/write by user */ - unsigned int status; /* Read/write by user */ - unsigned char userhdr[ZT_TRANSCODE_HDRLEN - (sizeof(unsigned int) * 14)]; /* Storage for user parameters */ - unsigned char srcdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of source data */ - unsigned char dstdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of destination data */ -} ZT_TRANSCODE_HEADER; - struct zt_ring_cadence { int ringcadence[ZT_MAX_CADENCE]; }; @@ -1711,27 +1682,74 @@ struct zt_transcoder_channel { void *pvt; struct zt_transcoder *parent; wait_queue_head_t ready; - int errorstatus; - int offset; - unsigned int chan_built; - unsigned int built_fmts; - unsigned int flags; - unsigned int srcfmt; - unsigned int dstfmt; - struct zt_transcode_header *tch; + __u32 built_fmts; +#define ZT_TC_FLAG_BUSY 1 +#define ZT_TC_FLAG_CHAN_BUILT 2 +#define ZT_TC_FLAG_NONBLOCK 3 +#define ZT_TC_FLAG_DATA_WAITING 4 + unsigned long flags; + u32 dstfmt; + u32 srcfmt; }; -#define ZT_TC_FLAG_BUSY (1 << 0) -#define ZT_TC_FLAG_TRANSIENT (1 << 1) - +static inline int +zt_tc_is_built(struct zt_transcoder_channel *dtc) { + return test_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags); +} +static inline void +zt_tc_set_built(struct zt_transcoder_channel *dtc) { + set_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags); +} +static inline void +zt_tc_clear_built(struct zt_transcoder_channel *dtc) { + clear_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags); +} +static inline int +zt_tc_is_nonblock(struct zt_transcoder_channel *dtc) { + return test_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags); +} +static inline void +zt_tc_set_nonblock(struct zt_transcoder_channel *dtc) { + set_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags); +} +static inline void +zt_tc_clear_nonblock(struct zt_transcoder_channel *dtc) { + clear_bit(ZT_TC_FLAG_NONBLOCK, &dtc->flags); +} +static inline int +zt_tc_is_data_waiting(struct zt_transcoder_channel *dtc) { + return test_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags); +} +static inline int +zt_tc_is_busy(struct zt_transcoder_channel *dtc) { + return test_bit(ZT_TC_FLAG_BUSY, &dtc->flags); +} +static inline void +zt_tc_set_busy(struct zt_transcoder_channel *dtc) { + set_bit(ZT_TC_FLAG_BUSY, &dtc->flags); +} +static inline void +zt_tc_clear_busy(struct zt_transcoder_channel *dtc) { + clear_bit(ZT_TC_FLAG_BUSY, &dtc->flags); +} +static inline void +zt_tc_set_data_waiting(struct zt_transcoder_channel *dtc) { + set_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags); +} +static inline void +zt_tc_clear_data_waiting(struct zt_transcoder_channel *dtc) { + clear_bit(ZT_TC_FLAG_DATA_WAITING, &dtc->flags); +} struct zt_transcoder { - struct zt_transcoder *next; + struct list_head node; char name[80]; int numchannels; unsigned int srcfmts; unsigned int dstfmts; - int (*operation)(struct zt_transcoder_channel *channel, int op); + struct file_operations fops; + int (*allocate)(struct zt_transcoder_channel *channel); + int (*release)(struct zt_transcoder_channel *channel); /* Transcoder channels */ struct zt_transcoder_channel channels[0]; }; diff --git a/kernel/zttranscode.c b/kernel/zttranscode.c index e44895b..23a5dc8 100644 --- a/kernel/zttranscode.c +++ b/kernel/zttranscode.c @@ -3,7 +3,7 @@ * * Written by Mark Spencer * - * Copyright (C) 2006-2007, Digium, Inc. + * Copyright (C) 2006-2008, Digium, Inc. * * All rights reserved. * @@ -35,20 +35,11 @@ #include #include #include -#ifdef CONFIG_DEVFS_FS -#include -#endif -#ifdef STANDALONE_ZAPATA -#include "zaptel.h" -#else -#include -#endif -#ifdef LINUX26 -#include -#endif -static int debug = 0; -static struct zt_transcoder *trans; +#include + +static int debug; +LIST_HEAD(trans); static spinlock_t translock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(zt_transcoder_register); @@ -59,387 +50,375 @@ EXPORT_SYMBOL(zt_transcoder_free); struct zt_transcoder *zt_transcoder_alloc(int numchans) { - struct zt_transcoder *ztc; + struct zt_transcoder *tc; unsigned int x; - size_t size = sizeof(*ztc) + (sizeof(ztc->channels[0]) * numchans); + size_t size = sizeof(*tc) + (sizeof(tc->channels[0]) * numchans); - if (!(ztc = kmalloc(size, GFP_KERNEL))) + if (!(tc = kmalloc(size, GFP_KERNEL))) return NULL; - memset(ztc, 0, size); - strcpy(ztc->name, ""); - ztc->numchannels = numchans; - for (x=0;xnumchannels;x++) { - init_waitqueue_head(&ztc->channels[x].ready); - ztc->channels[x].parent = ztc; - ztc->channels[x].offset = x; - ztc->channels[x].chan_built = 0; - ztc->channels[x].built_fmts = 0; + memset(tc, 0, size); + strcpy(tc->name, ""); + tc->numchannels = numchans; + for (x=0;xnumchannels;x++) { + init_waitqueue_head(&tc->channels[x].ready); + INIT_LIST_HEAD(&tc->node); + tc->channels[x].parent = tc; } - return ztc; + WARN_ON(!zt_transcode_fops); + /* Individual transcoders should supply their own file_operations for + * write and read. But they will by default use the file_operations + * provided by the zt_transcode layer. */ + memcpy(&tc->fops, zt_transcode_fops, sizeof(*zt_transcode_fops)); + return tc; } -static int schluffen(wait_queue_head_t *q) +void zt_transcoder_free(struct zt_transcoder *tc) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(q, &wait); - current->state = TASK_INTERRUPTIBLE; - - if (!signal_pending(current)) - schedule(); - - current->state = TASK_RUNNING; - remove_wait_queue(q, &wait); - - if (signal_pending(current)) - return -ERESTARTSYS; - - return 0; + kfree(tc); } -void zt_transcoder_free(struct zt_transcoder *ztc) +/* Returns 1 if the item is on the list pointed to by head, otherwise, returns + * 0 */ +static int is_on_list(struct list_head *entry, struct list_head *head) { - kfree(ztc); + struct list_head *cur; + list_for_each(cur, head) { + if (cur == entry) return 1; + } + return 0; } /* Register a transcoder */ int zt_transcoder_register(struct zt_transcoder *tc) { - struct zt_transcoder *cur; - int res = -EBUSY; - spin_lock(&translock); - for (cur = trans; cur; cur = cur->next) { - if (cur == tc) { - spin_unlock(&translock); - return res; - } - } - - tc->next = trans; - trans = tc; - printk("Registered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n", - tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts); - res = 0; + BUG_ON(is_on_list(&tc->node, &trans)); + list_add_tail(&tc->node, &trans); spin_unlock(&translock); - return res; + printk(KERN_INFO "%s: Registered codec translator '%s' " \ + "with %d transcoders (srcs=%08x, dsts=%08x)\n", + THIS_MODULE->name, tc->name, tc->numchannels, + tc->srcfmts, tc->dstfmts); + + return 0; } /* Unregister a transcoder */ int zt_transcoder_unregister(struct zt_transcoder *tc) { - struct zt_transcoder *cur, *prev; int res = -EINVAL; - spin_lock(&translock); - for (cur = trans, prev = NULL; cur; prev = cur, cur = cur->next) { - if (cur == tc) - break; - } + /* \todo Perhaps we should check to make sure there isn't a channel + * that is still in use? */ - if (!cur) { + spin_lock(&translock); + if (!is_on_list(&tc->node, &trans)) { spin_unlock(&translock); - return res; + printk(KERN_WARNING "%s: Failed to unregister %s, which is " \ + "not currently registerd.\n", THIS_MODULE->name, tc->name); + return -EINVAL; } + list_del_init(&tc->node); + spin_unlock(&translock); - if (prev) - prev->next = tc->next; - else - trans = tc->next; - tc->next = NULL; - printk("Unregistered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n", + printk(KERN_INFO "Unregistered codec translator '%s' with %d " \ + "transcoders (srcs=%08x, dsts=%08x)\n", tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts); res = 0; - spin_unlock(&translock); return res; } /* Alert a transcoder */ -int zt_transcoder_alert(struct zt_transcoder_channel *ztc) +int zt_transcoder_alert(struct zt_transcoder_channel *chan) { - if (debug) - printk("ZT Transcoder Alert!\n"); - if (ztc->tch) - ztc->tch->status &= ~ZT_TC_FLAG_BUSY; - wake_up_interruptible(&ztc->ready); - + wake_up_interruptible(&chan->ready); return 0; } static int zt_tc_open(struct inode *inode, struct file *file) { - struct zt_transcoder_channel *ztc; - struct zt_transcode_header *zth; - struct page *page; - - if (!(ztc = kmalloc(sizeof(*ztc), GFP_KERNEL))) - return -ENOMEM; - - if (!(zth = kmalloc(sizeof(*zth), GFP_KERNEL | GFP_DMA))) { - kfree(ztc); - return -ENOMEM; - } - - memset(ztc, 0, sizeof(*ztc)); - memset(zth, 0, sizeof(*zth)); - ztc->flags = ZT_TC_FLAG_TRANSIENT | ZT_TC_FLAG_BUSY; - ztc->tch = zth; - if (debug) - printk("Allocated Transcoder Channel, header is at %p!\n", zth); - zth->magic = ZT_TRANSCODE_MAGIC; - file->private_data = ztc; - for (page = virt_to_page(zth); - page < virt_to_page((unsigned long) zth + sizeof(*zth)); - page++) - SetPageReserved(page); - + const struct file_operations *original_fops; + BUG_ON(!zt_transcode_fops); + original_fops = file->f_op; + file->f_op = zt_transcode_fops; + file->private_data = NULL; + /* Under normal operation, this releases the reference on the Zaptel + * module that was created when the file was opened. zt_open is + * responsible for taking a reference out on this module before + * calling this function. */ + module_put(original_fops->owner); return 0; } -static void ztc_release(struct zt_transcoder_channel *ztc) +static void dtc_release(struct zt_transcoder_channel *chan) { - struct zt_transcode_header *zth = ztc->tch; - struct page *page; - - if (!ztc) - return; - - ztc->flags &= ~(ZT_TC_FLAG_BUSY); - - if(ztc->tch) { - for (page = virt_to_page(zth); - page < virt_to_page((unsigned long) zth + sizeof(*zth)); - page++) - ClearPageReserved(page); - kfree(ztc->tch); + BUG_ON(!chan); + if (chan->parent && chan->parent->release) { + chan->parent->release(chan); } - - ztc->tch = NULL; - /* Actually reset the transcoder channel */ - if (ztc->flags & ZT_TC_FLAG_TRANSIENT) - kfree(ztc); - if (debug) - printk("Released Transcoder!\n"); + zt_tc_clear_busy(chan); } static int zt_tc_release(struct inode *inode, struct file *file) { - ztc_release(file->private_data); - + struct zt_transcoder_channel *chan = file->private_data; + /* There will not be a transcoder channel associated with this file if + * the ALLOCATE ioctl never succeeded. + */ + if (chan) { + dtc_release(chan); + } return 0; } -static int do_reset(struct zt_transcoder_channel **ztc) +/* Find a free channel on the transcoder and mark it busy. */ +static inline struct zt_transcoder_channel * +get_free_channel(struct zt_transcoder *tc) + +{ + struct zt_transcoder_channel *chan; + int i; + /* Should be called with the translock held. */ + WARN_ON(!spin_is_locked(&translock)); + + for (i = 0; i < tc->numchannels; i++) { + chan = &tc->channels[i]; + if (!zt_tc_is_busy(chan)) { + zt_tc_set_busy(chan); + return chan; + } + } + return NULL; +} + +/* Search the list for a transcoder that supports the specified format, and + * allocate and return an available channel on it. + * + * Returns either a pointer to the allocated channel, -EBUSY if the format is + * supported but all the channels are busy, or -ENODEV if there are not any + * transcoders that support the formats. + */ +static struct zt_transcoder_channel * +__find_free_channel(struct list_head *list, const struct zt_transcoder_formats *fmts) { - struct zt_transcoder_channel *newztc = NULL, *origztc = NULL; - struct zt_transcode_header *zth = (*ztc)->tch; struct zt_transcoder *tc; - unsigned int x; + struct zt_transcoder_channel *chan = NULL; unsigned int match = 0; - if (((*ztc)->srcfmt != zth->srcfmt) || - ((*ztc)->dstfmt != zth->dstfmt)) { - /* Find new transcoder */ - spin_lock(&translock); - for (tc = trans; tc && !newztc; tc = tc->next) { - if (!(tc->srcfmts & zth->srcfmt)) - continue; - - if (!(tc->dstfmts & zth->dstfmt)) - continue; - - match = 1; - for (x = 0; x < tc->numchannels; x++) { - if (tc->channels[x].flags & ZT_TC_FLAG_BUSY) - continue; - if ((tc->channels[x].chan_built) && ((zth->srcfmt | zth->dstfmt) != tc->channels[x].built_fmts)) - continue; - - newztc = &tc->channels[x]; - newztc->flags = ZT_TC_FLAG_BUSY; - break; + list_for_each_entry(tc, list, node) { + if ((tc->dstfmts & fmts->dstfmt)) { + /* We found a transcoder that can handle our formats. + * Now look for an available channel. */ + match = 1; + if ((chan = get_free_channel(tc))) { + /* transcoder tc has a free channel. In order + * to spread the load among available + * transcoders (when there are more than one + * transcoder in the system) we'll move tc + * to the end of the list. */ + list_move_tail(&tc->node, list); + return chan; } } - spin_unlock(&translock); + } + return (void*)((long)((match) ? -EBUSY : -ENODEV)); +} - if (!newztc) - return match ? -EBUSY : -ENOSYS; +static long zt_tc_allocate(struct file *file, unsigned long data) +{ + struct zt_transcoder_channel *chan = NULL; + struct zt_transcoder_formats fmts; + + if (copy_from_user(&fmts, + (struct zt_transcoder_formats*) data, sizeof(fmts))) { + return -EFAULT; + } + + spin_lock(&translock); + chan = __find_free_channel(&trans, &fmts); + spin_unlock(&translock); - /* Move transcoder header over */ - origztc = (*ztc); - (*ztc) = newztc; - (*ztc)->tch = origztc->tch; - origztc->tch = NULL; - (*ztc)->flags |= (origztc->flags & ~(ZT_TC_FLAG_TRANSIENT)); - ztc_release(origztc); + if (IS_ERR(chan)) { + return PTR_ERR(chan); } - /* Actually reset the transcoder channel */ - if ((*ztc)->parent && ((*ztc)->parent->operation)) - return (*ztc)->parent->operation((*ztc), ZT_TCOP_ALLOCATE); + /* Every transcoder channel must be associated with a parent + * transcoder. */ + BUG_ON(!chan->parent); - return -EINVAL; -} + chan->srcfmt = fmts.srcfmt; + chan->dstfmt = fmts.dstfmt; -static int wait_busy(struct zt_transcoder_channel *ztc) -{ - int ret; + if (file->private_data) { + /* This open file is moving to a new channel. Cleanup and + * close the old channel here. */ + dtc_release(file->private_data); + } + + file->private_data = chan; + if (chan->parent->fops.owner != file->f_op->owner) { + if (!try_module_get(chan->parent->fops.owner)) { + /* Failed to get a reference on the driver for the + * actual transcoding hardware. */ + return -EINVAL; + } + /* Release the reference on the existing driver. */ + module_put(file->f_op->owner); + file->f_op = &chan->parent->fops; + } - for (;;) { - if (!(ztc->tch->status & ZT_TC_FLAG_BUSY)) - return 0; - if ((ret = schluffen(&ztc->ready))) - return ret; + if (file->f_flags & O_NONBLOCK) { + zt_tc_set_nonblock(chan); + } else { + zt_tc_clear_nonblock(chan); } + + /* Actually reset the transcoder channel */ + if (chan->parent->allocate) + return chan->parent->allocate(chan); + + return -EINVAL; } -static int zt_tc_getinfo(unsigned long data) +static long zt_tc_getinfo(unsigned long data) { - struct zt_transcode_info info; + struct zt_transcoder_info info; unsigned int x; - struct zt_transcoder *tc; + struct zt_transcoder *cur; + struct zt_transcoder *tc = NULL; - if (copy_from_user(&info, (struct zt_transcode_info *) data, sizeof(info))) + if (copy_from_user(&info, (const void *) data, sizeof(info))) { return -EFAULT; + } + x = 0; spin_lock(&translock); - for (tc = trans, x = info.tcnum; tc && x; tc = tc->next, x--); + list_for_each_entry(cur, &trans, node) { + if (x++ == info.tcnum) { + tc = cur; + break; + } + } spin_unlock(&translock); - if (!tc) + if (!tc) { return -ENOSYS; + } zap_copy_string(info.name, tc->name, sizeof(info.name)); info.numchannels = tc->numchannels; info.srcfmts = tc->srcfmts; info.dstfmts = tc->dstfmts; - return copy_to_user((struct zt_transcode_info *) data, &info, sizeof(info)) ? -EFAULT : 0; + return copy_to_user((void *) data, &info, sizeof(info)) ? -EFAULT : 0; } -static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) +static ssize_t zt_tc_write(struct file *file, __user const char *usrbuf, size_t count, loff_t *ppos) { - int op; - int ret; - struct zt_transcoder_channel *ztc = file->private_data; - - if (cmd != ZT_TRANSCODE_OP) + if (file->private_data) { + /* file->private_data will not be NULL if ZT_TC_ALLOCATE was + * called, and therefore indicates that the transcoder driver + * did not export a read function. */ + WARN_ON(1); return -ENOSYS; - - if (get_user(op, (int *) data)) - return -EFAULT; - - if (debug) - printk("ZT Transcode ioctl op = %d!\n", op); - - switch(op) { - case ZT_TCOP_GETINFO: - ret = zt_tc_getinfo(data); - break; - case ZT_TCOP_ALLOCATE: - /* Reset transcoder, possibly changing who we point to */ - ret = do_reset(&ztc); - file->private_data = ztc; - break; - case ZT_TCOP_RELEASE: - ret = ztc->parent->operation(ztc, ZT_TCOP_RELEASE); - break; - case ZT_TCOP_TEST: - ret = ztc->parent->operation(ztc, ZT_TCOP_TEST); - break; - case ZT_TCOP_TRANSCODE: - if (!ztc->parent->operation) - return -EINVAL; - - ztc->tch->status |= ZT_TC_FLAG_BUSY; - if (!(ret = ztc->parent->operation(ztc, ZT_TCOP_TRANSCODE))) { - /* Wait for busy to go away if we're not non-blocking */ - if (!(file->f_flags & O_NONBLOCK)) { - if (!(ret = wait_busy(ztc))) - ret = ztc->errorstatus; - } - } else - ztc->tch->status &= ~ZT_TC_FLAG_BUSY; - break; - default: - ret = -ENOSYS; + } else { + printk(KERN_INFO "%s: Attempt to write to unallocated " \ + "channel.\n", THIS_MODULE->name); + return -EINVAL; } - - return ret; } -static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma) +static ssize_t zt_tc_read(struct file *file, __user char *usrbuf, size_t count, loff_t *ppos) { - struct zt_transcoder_channel *ztc = file->private_data; - unsigned long physical; - int res; - - if (!ztc) - return -EINVAL; - - /* Do not allow an offset */ - if (vma->vm_pgoff) { - if (debug) - printk("zttranscode: Attempted to mmap with offset!\n"); + if (file->private_data) { + /* file->private_data will not be NULL if ZT_TC_ALLOCATE was + * called, and therefore indicates that the transcoder driver + * did not export a write function. */ + WARN_ON(1); + return -ENOSYS; + } else { + printk(KERN_INFO "%s: Attempt to read from unallocated " \ + "channel.\n", THIS_MODULE->name); return -EINVAL; } +} - if ((vma->vm_end - vma->vm_start) != sizeof(struct zt_transcode_header)) { - if (debug) - printk("zttranscode: Attempted to mmap with size %d != %zd!\n", (int) (vma->vm_end - vma->vm_start), sizeof(struct zt_transcode_header)); +static long zt_tc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data) +{ + switch (cmd) { + case ZT_TC_ALLOCATE: + return zt_tc_allocate(file, data); + case ZT_TC_GETINFO: + return zt_tc_getinfo(data); + case ZT_TRANSCODE_OP: + /* This is a deprecated call from the previous transcoder + * interface, which was all routed through the zt_ioctl in + * zaptel-base.c, and this ioctl request was used to indicate + * that the call should be forwarded to this function. Now + * when the file is opened, the f_ops pointer is updated to + * point directly to this function, and we don't need a + * general indication that the ioctl is destined for the + * transcoder. + * + * I'm keeping this ioctl here in order to explain why there + * might be a hole in the ioctl numbering scheme in the header + * files. + */ + printk(KERN_WARNING "%s: ZT_TRANSCODE_OP is no longer " \ + "supported. Please call ZT_TC ioctls directly.\n", + THIS_MODULE->name); return -EINVAL; - } - - physical = (unsigned long) virt_to_phys(ztc->tch); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) - res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, sizeof(struct zt_transcode_header), PAGE_SHARED); -#else - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - res = remap_page_range(vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED); - #else - res = remap_page_range(vma, vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED); - #endif -#endif - if (res) { - if (debug) - printk("zttranscode: remap failed!\n"); - return -EAGAIN; - } + default: + return -EINVAL; + }; +} - if (debug) - printk("zttranscode: successfully mapped transcoder!\n"); +static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) +{ + return (int)zt_tc_unlocked_ioctl(file, cmd, data); +} - return 0; +static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma) +{ + printk(KERN_ERR "%s: mmap interface deprecated.\n", THIS_MODULE->name); + return -ENOSYS; } static unsigned int zt_tc_poll(struct file *file, struct poll_table_struct *wait_table) { - struct zt_transcoder_channel *ztc = file->private_data; + int ret; + struct zt_transcoder_channel *chan = file->private_data; - if (!ztc) + if (!chan) { + /* This is because the ZT_TC_ALLOCATE ioctl was not called + * before calling poll, which is invalid. */ return -EINVAL; + } - poll_wait(file, &ztc->ready, wait_table); - return ztc->tch->status & ZT_TC_FLAG_BUSY ? 0 : POLLPRI; + poll_wait(file, &chan->ready, wait_table); + + ret = zt_tc_is_busy(chan) ? 0 : POLLPRI; + ret |= zt_tc_is_built(chan) ? POLLOUT : 0; + ret |= zt_tc_is_data_waiting(chan) ? POLLIN : 0; + return ret; } static struct file_operations __zt_transcode_fops = { - owner: THIS_MODULE, - llseek: NULL, - open: zt_tc_open, + owner: THIS_MODULE, + open: zt_tc_open, release: zt_tc_release, - ioctl: zt_tc_ioctl, - read: NULL, - write: NULL, - poll: zt_tc_poll, - mmap: zt_tc_mmap, - flush: NULL, - fsync: NULL, - fasync: NULL, + ioctl: zt_tc_ioctl, + read: zt_tc_read, + write: zt_tc_write, + poll: zt_tc_poll, + mmap: zt_tc_mmap, +#if HAVE_UNLOCKED_IOCTL + unlocked_ioctl: zt_tc_unlocked_ioctl, +#endif }; static struct zt_chardev transcode_chardev = { @@ -447,12 +426,12 @@ static struct zt_chardev transcode_chardev = { .minor = 250, }; -int zttranscode_init(void) +int zt_transcode_init(void) { int res; if (zt_transcode_fops) { - printk("Whoa, zt_transcode_fops already set?!\n"); + printk(KERN_WARNING "zt_transcode_fops already set.\n"); return -EBUSY; } @@ -461,30 +440,25 @@ int zttranscode_init(void) if ((res = zt_register_chardev(&transcode_chardev))) return res; - printk("Zaptel Transcoder support loaded\n"); - + printk(KERN_INFO "%s: Loaded.\n", THIS_MODULE->name); return 0; } -void zttranscode_cleanup(void) +void zt_transcode_cleanup(void) { zt_unregister_chardev(&transcode_chardev); zt_transcode_fops = NULL; - printk("Zaptel Transcoder support unloaded\n"); + printk(KERN_DEBUG "%s: Unloaded.\n", THIS_MODULE->name); } -#ifdef LINUX26 module_param(debug, int, S_IRUGO | S_IWUSR); -#else -MODULE_PARM(debug, "i"); -#endif MODULE_DESCRIPTION("Zaptel Transcoder Support"); MODULE_AUTHOR("Mark Spencer "); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif -module_init(zttranscode_init); -module_exit(zttranscode_cleanup); +module_init(zt_transcode_init); +module_exit(zt_transcode_cleanup); -- cgit v1.2.3